如何在SvelteKit+静态适配器中缓存Strapi API获取的图片?
解决方案:在SvelteKit中缓存Strapi图片并静态生成站点
方法一:构建前自定义脚本批量下载图片
直接编写Node.js脚本,在SvelteKit构建前从Strapi拉取所有媒体资源,保存到项目static目录,同时替换API返回内容里的图片链接为本地路径。
步骤:
- 在项目根目录新建
scripts/download-strapi-images.js脚本:
import fs from 'fs/promises'; import path from 'path'; import fetch from 'node-fetch'; const STRAPI_API_URL = 'https://your-strapi-instance.com/api'; const IMAGE_DEST_DIR = path.join(process.cwd(), 'static', 'strapi-images'); async function downloadImage(url, filename) { const res = await fetch(url); const buffer = await res.buffer(); await fs.mkdir(IMAGE_DEST_DIR, { recursive: true }); await fs.writeFile(path.join(IMAGE_DEST_DIR, filename), buffer); } async function fetchAndProcessContent() { // 拉取作品集条目等目标内容 const contentRes = await fetch(`${STRAPI_API_URL}/portfolio-items?populate=*`); const contentData = await contentRes.json(); // 遍历下载图片并替换链接 for (const item of contentData.data) { if (item.attributes.image) { const strapiImageUrl = item.attributes.image.data.attributes.url; const imageFilename = strapiImageUrl.split('/').pop(); // 拼接完整Strapi图片地址(去掉API路径前缀) await downloadImage(`${STRAPI_API_URL.replace('/api', '')}${strapiImageUrl}`, imageFilename); // 替换为本地静态资源路径 item.attributes.image.data.attributes.url = `/strapi-images/${imageFilename}`; } } // 把处理后的内容存为本地JSON,供页面加载 await fs.writeFile(path.join(process.cwd(), 'src', 'data', 'portfolio.json'), JSON.stringify(contentData)); } fetchAndProcessContent().catch(err => console.error(err));
- 在
package.json的scripts中添加构建前置命令:
{ "scripts": { "prebuild": "node scripts/download-strapi-images.js", "build": "vite build" } }
- 页面中直接读取本地JSON文件加载内容,预渲染时生成的HTML会自动使用本地图片链接。
方法二:预渲染时动态下载图片(适配SvelteKit prerender)
利用SvelteKit的预渲染机制,在页面/布局的load函数中抓取Strapi内容,同时下载图片到static目录,返回修改后的链接给页面组件。
- 先在
src/routes/+layout.js中开启预渲染:
export const prerender = true; export const ssr = true;
- 在页面的
+page.server.js中处理图片下载与链接替换:
import fs from 'fs/promises'; import path from 'path'; import fetch from 'node-fetch'; const STRAPI_API_URL = 'https://your-strapi-instance.com/api'; const IMAGE_DEST_DIR = path.join(process.cwd(), 'static', 'strapi-images'); export async function load() { const contentRes = await fetch(`${STRAPI_API_URL}/portfolio-items?populate=*`); const contentData = await contentRes.json(); for (const item of contentData.data) { if (item.attributes.image) { const strapiImagePath = item.attributes.image.data.attributes.url; const imageUrl = `${STRAPI_API_URL.replace('/api', '')}${strapiImagePath}`; const imageFilename = strapiImagePath.split('/').pop(); const localPath = path.join(IMAGE_DEST_DIR, imageFilename); // 检查是否已下载,避免重复请求 try { await fs.access(localPath); } catch { const res = await fetch(imageUrl); const buffer = await res.buffer(); await fs.mkdir(IMAGE_DEST_DIR, { recursive: true }); await fs.writeFile(localPath, buffer); } // 替换为本地相对链接 item.attributes.image.data.attributes.url = `/strapi-images/${imageFilename}`; } } return { portfolioItems: contentData.data }; }
预渲染时SvelteKit会执行load函数下载图片,生成的静态HTML里的图片链接会指向本地static目录,构建完成后无需Strapi运行即可正常展示。
注意事项
- 确保Strapi媒体文件公开可访问,若需权限,要在请求中携带API Token。
- 可以用图片ID或哈希值作为文件名,避免重名覆盖。
- Strapi内容更新后,需重新执行构建流程同步新内容与图片。
内容的提问来源于stack exchange,提问作者werls
相关产品推荐
相关产品推荐

