图片、字体、图标等静态资源
- Standard:静态资源按类型分类存放,禁止混放。
| 类型 | 目录 | 说明 |
|---|
| 图片 | src/assets/images/ | PNG、JPG、WebP、SVG、GIF |
| 图标 | src/assets/icons/ | SVG 图标、iconfont |
| 字体 | src/assets/fonts/ | WOFF2、WOFF、TTF |
| 视频 | src/assets/videos/ | MP4、WebM |
| 音频 | src/assets/audios/ | MP3、WAV |
| 其他 | src/assets/misc/ | JSON、模型文件等 |
- Requirement:需要在构建产物中保留原始路径与文件名的资源放在
public/ 目录,不经过构建处理。
- Requirement:需要经过构建处理(压缩、哈希、转换)的资源放在
src/assets/ 目录。
| 目录 | 处理方式 | 适用场景 |
|---|
public/ | 原样复制到产物根目录 | favicon、robots.txt、manifest.json、不常变的大文件 |
src/assets/ | 经过构建工具处理(压缩、hash、转 base64) | 页面内引用的图片、字体、图标 |
│ ├── inter-regular.woff2
- Requirement:资源文件名全部小写,使用连字符
- 分隔单词,禁止使用空格、中文、下划线、驼峰。
- Requirement:文件名应语义化,描述资源内容,禁止使用无意义名称(如
img1.png、未命名.png)。
| 正确 | 错误 |
|---|
logo.png | LOGO.png |
user-avatar-default.svg | userAvatarDefault.svg |
payment-success.png | payment_success.png |
arrow-left.svg | arrowleft.svg |
empty-cart.png | 空购物车.png |
bg-homepage.webp | bg1.webp |
- Standard:同一图片的不同尺寸在文件名末尾标注尺寸,格式为
<name>-<width>x<height>.<ext>。
- Standard:图标资源如有多状态,在文件名末尾标注状态。
icon-success-disabled.svg
- Standard:优先使用现代图片格式 WebP / AVIF,兼容性要求高时提供 PNG/JPG 降级。
- Standard:照片类图片使用 JPG/WebP,图标/透明图使用 SVG/WebP,动画使用 GIF/WebP/APNG。
| 场景 | 推荐格式 | 说明 |
|---|
| 照片、复杂图像 | WebP / JPG | 体积小、有损压缩 |
| 图标、Logo、矢量图 | SVG | 无损、可缩放、体积小 |
| 简单图形、透明图 | WebP / PNG | 支持透明 |
| 动画 | WebP / APNG | 优先 WebP,体积更小 |
- Standard:单张图片体积建议 ≤ 200KB,超过需评估是否压缩或拆分。
- Standard:首屏关键图片 ≤ 50KB,非首屏图片懒加载。
- Caution:禁止直接使用原图(相机、设计稿导出的未压缩图)。
- Standard:构建时自动压缩图片,推荐使用:
imagemin / sharp(Node 生态)
image-minimizer-webpack-plugin(Webpack)
vite-plugin-imagemin(Vite)
- Standard:SVG 使用
svgo 优化,移除冗余元数据。
// vite.config.ts
import { defineConfig } from 'vite';
import imagemin from 'vite-plugin-imagemin';
export default defineConfig({
plugins: [
imagemin({
gifsicle: { optimizationLevel: 7 },
optipng: { optimizationLevel: 7 },
mozjpeg: { quality: 80 },
pngquant: { quality: [0.8, 0.9] },
svgo: {
plugins: [{ removeViewBox: false }],
},
webp: { quality: 75 },
}),
],
});
- Standard:不同分辨率设备使用不同尺寸图片,通过
srcset 提供多尺寸。
<img
src="/images/banner-640.webp"
srcset="/images/banner-640.webp 640w, /images/banner-1280.webp 1280w, /images/banner-1920.webp 1920w"
sizes="(max-width: 640px) 100vw, 1280px"
alt="banner"
loading="lazy"
/>
- Standard:字体文件仅引入 WOFF2 格式(现代浏览器均支持),如需兼容旧浏览器再补充 WOFF。
- Standard:使用
font-display: swap 避免 FOIT(Flash of Invisible Text)。
- Standard:仅引入实际使用的字重,避免全量引入。
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
- Caution:禁止引入整个字体家族(如包含所有字重的 TTF),体积过大。
- Standard:生产环境静态资源必须上传 CDN,通过 CDN 域名访问。
- Standard:CDN 域名与主站域名分离,如
https://cdn.example.com/static/。
- Caution:禁止将大体积资源(> 5MB)打包到 JS/CSS 中,应独立存放并通过 CDN 加载。
- Standard:构建时自动替换资源引用路径为 CDN 路径。
// vite.config.ts
export default defineConfig({
base: process.env.NODE_ENV === 'production'
? 'https://cdn.example.com/static/'
: '/',
});
- Standard:使用独立的 CDN 域名,避免与主站共用 Cookie(减少请求开销)。
- Standard:国内项目使用国内 CDN(阿里云、腾讯云),海外项目使用 Cloudflare / AWS CloudFront。
- Standard:带 hash 文件名的资源(如
logo.3a2b1c.png)设置长期缓存(1 年)。
- Standard:不带 hash 的资源(如
favicon.ico)设置短缓存或不缓存。
- Standard:HTML 文件不缓存,确保用户获取最新版本。
| 资源类型 | Cache-Control | 说明 |
|---|
| HTML | no-cache | 每次协商缓存 |
| 带 hash 的 JS/CSS/图片 | public, max-age=31536000, immutable | 长期缓存 |
| 不带 hash 的图片/字体 | public, max-age=86400 | 1 天缓存 |
| favicon | public, max-age=604800 | 7 天缓存 |
- Requirement:构建产物中的资源文件名必须包含内容 hash,确保更新后缓存失效。
- Standard:hash 长度建议 8 位,兼顾唯一性与可读性。
- Standard:资源内容变更时,文件名 hash 自动变化,浏览器自动拉取新版本。
- Caution:禁止修改已发布的带 hash 资源文件内容,必须生成新文件。
| 反模式 | 问题 | 建议 |
|---|
| 中文文件名 | 编码问题、URL 编码异常 | 使用英文小写 + 连字符 |
| 直接使用设计稿原图 | 体积过大、加载慢 | 压缩后再使用 |
| 所有图片用 PNG | 体积大 | 照片用 JPG/WebP |
| 引入全量字体文件 | 首屏加载慢 | 仅引入需要的字重 |
| 资源不带 hash 文件名 | 缓存无法自动失效 | 构建时自动加 hash |
| 大体积图片放在首屏 | 白屏时间长 | 压缩 + 懒加载 |
| 资源引用使用本地绝对路径 | 部署后路径错误 | 使用相对路径或 CDN 路径 |
| SVG 未优化 | 包含冗余元数据、体积大 | 使用 svgo 优化 |
| CDN 与主站同域名 | 携带无用 Cookie | 使用独立 CDN 域名 |