4.1 public vs src/assets
这是第一次用 Vite 最容易混淆的概念:
| 位置 | 是否参与构建 | URL | 典型用途 |
|---|---|---|---|
public/ | ❌ 不参与 | /foo.png | favicon、robots.txt、不需要处理的第三方脚本 |
src/assets/ | ✅ 参与 | 由 import 生成哈希文件名 | 业务用图片/字体/SVG,需要缓存与 tree-shaking |
// src 里的资源必须 import,否则不会被打包
import logoUrl from './assets/logo.png';
<img src={logoUrl} />
// public 里的资源用绝对路径,不需要 import
<img src="/favicon.png" />
public 里的文件不会被处理
不做 hash、不做压缩、不检查是否存在。所以业务图片应该放 src/,只有那些"必须保持固定路径"的文件才放 public/。
4.2 资源导入的三种形态
// 1. 默认:返回解析后的 URL(生产带 hash)
import imgUrl from './img.png';
// imgUrl === "/assets/img-Dh8a3K.png"
// 2. ?url 显式要 URL(等价默认)
import imgUrl from './img.png?url';
// 3. ?raw 把内容作为字符串 inline
import shader from './shader.glsl?raw';
// shader === "precision mediump float; void main(){..."
// 4. ?inline 强制 base64 data URL(即使超过阈值)
import iconDataUrl from './icon.svg?inline';
4.3 动态 URL:import.meta.url
相对路径变量化时,不能直接拼字符串:
// ❌ 错:Vite 静态分析不到 './img1.png',不会打包
const url = `./assets/${name}.png`;
// ✅ 对:用 new URL + import.meta.url,Rollup 会识别
const url = new URL(`./assets/${name}.png`, import.meta.url).href;
import.meta.url 是什么?
ESM 标准 API,返回当前模块所在的 URL。在 Vite 中,它会被替换成构建后的正确路径。这是构造运行时相对路径的唯一安全方法。
4.4 Glob 导入:import.meta.glob
一次性导入一堆文件?webpack 里要用 require.context;Vite 提供官方等价物:
// 懒加载(默认)
const modules = import.meta.glob('./pages/*.vue');
// modules = { './pages/a.vue': () => import('./pages/a.vue'), ... }
// 急切加载:eager: true
const modules = import.meta.glob('./pages/*.vue', { eager: true });
// 拿原始文本
const docs = import.meta.glob('./docs/*.md', { query: '?raw', import: 'default' });
4.5 CSS 基本用法
// 直接 import 会把 CSS 注入页面
import './app.css';
// 拿到 CSS 字符串(通常不用)
import css from './app.css?inline';
4.6 CSS Modules
文件名后缀 .module.css/.module.scss 自动启用:
/* Button.module.css */
.primary { background: #646cff; color: white; }
.disabled { opacity: 0.5; }
import styles from './Button.module.css';
function Button({ disabled, children }) {
return (
<button className={`${styles.primary} ${disabled ? styles.disabled : ''}`}>
{children}
</button>
);
}
构建后类名会变成 _primary_x7f92 这样的全局唯一哈希,避免冲突。
4.7 CSS Modules 配置
css: {
modules: {
// 类名格式(对 local 字段有效)
generateScopedName: '[name]__[local]__[hash:base64:5]',
// exportLocalsConvention: 小驼峰访问 —— styles.primaryButton 对应 .primary-button
localsConvention: 'camelCaseOnly',
},
}
4.8 预处理器:Sass / Less / Stylus
安装对应预处理器即用,Vite 自动识别后缀:
$ npm i -D sass
// App.vue
<style lang="scss">
$primary: #646cff;
.btn { background: $primary; }
</style>
css: {
preprocessorOptions: {
scss: {
// 每个 scss 自动注入
additionalData: `@use "@/styles/vars" as *;`,
},
},
},
4.9 PostCSS
Vite 内置 PostCSS 支持,在项目根放 postcss.config.js 即可:
// postcss.config.js
export default {
plugins: {
'postcss-preset-env': {},
'autoprefixer': {},
},
};
4.10 Tailwind CSS 集成
Tailwind v4(2025 年 GA)有官方 Vite 插件,集成比 v3 更干净:
$ npm i -D tailwindcss @tailwindcss/vite
// vite.config.ts
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
plugins: [tailwindcss()],
});
/* src/index.css */
@import "tailwindcss";
然后在组件里直接写 utility 类:
<button className="px-4 py-2 rounded bg-indigo-500 text-white hover:bg-indigo-600">
Click
</button>
4.11 字体文件
字体放 src/assets,通过 CSS @font-face 引用:
@font-face {
font-family: 'Inter';
src: url('@/assets/fonts/Inter.woff2') format('woff2');
font-display: swap;
}
Vite 会把 woff2 当资源处理,加上 hash、生产路径正确。
4.12 SVG 的多种玩法
// 1. 作为 URL(默认)
import iconUrl from './icon.svg';
// 2. 作为 raw SVG 字符串
import svgText from './icon.svg?raw';
// 3. 作为 React 组件(需 vite-plugin-svgr)
import Icon from './icon.svg?react';
<Icon width={24} />
4.13 JSON 导入
// 默认:整个对象
import pkg from '../package.json';
// 按字段(可 tree-shake)
import { version } from '../package.json';
4.14 小结
public/放不参与构建的资源,src/assets/放业务资源。- 查询后缀
?url/?raw/?inline/?react控制资源处理方式。 - 动态路径用
new URL(..., import.meta.url),不能拼字符串。 import.meta.glob是 webpackrequire.context的 Vite 等价物。- CSS Modules 用
.module.css自动启用;Tailwind v4 走@tailwindcss/vite插件。