Vite 默认开启 cssCodeSplit: true,但仅实现物理拆分而非按需加载;真正按需需依赖动态 import() 触发 CSS 打包进对应 chunk 并异步注入,静态 import 的样式始终进入主包。

默认开启 CSS 代码分割,但必须显式配置才能真正生效并控制分块行为。
为什么 cssCodeSplit: true 不等于“自动按需加载”
Vite 的 cssCodeSplit 默认为 true,但它只在构建时将不同入口或异步 chunk 中的 CSS 拆开成独立文件(比如 index-xxx.css 和 async-xxx.css),并不改变 CSS 的加载时机——所有生成的 CSS 文件仍会在 HTML 中被 <link> 同步插入,首屏仍会一次性加载全部样式。
- 常见错误现象:
Network面板看到多个 CSS 文件,但 FCP 时间没改善,render-blocking资源依然存在 - 根本原因:Vite 不会自动把 CSS 变成异步加载;它只是“物理拆分”,不是“逻辑懒加载”
- 真正起作用的是动态导入 + CSS in JS 或
import()触发的 chunk,此时对应的 CSS 才会随 JS chunk 异步加载
如何让 CSS 真正“按需加载”
只有当 CSS 来自动态导入模块(如路由组件、弹窗组件)时,Vite 才会把它打包进对应 chunk,并在该 chunk 加载时同步注入样式。这是唯一可靠的方式。
- Vue/React 路由中必须用
import():例如component: () => import('./views/Dashboard.vue'),且Dashboard.vue内的<style>才会被打到对应 chunk - 不要在根组件或 layout 中
@import全局样式——它们会进入主 chunk,无法拆分 - 避免使用
import './global.css'在入口文件里,改用link rel="stylesheet"手动引入关键 CSS(如重置、字体) - 第三方 UI 库(如 Ant Design、Element Plus)的样式必须跟随组件动态导入,否则仍会打进 vendor chunk
build.rollupOptions.output.manualChunks 对 CSS 无效
这个配置只影响 JS chunk 的拆分逻辑,对 CSS 文件命名、拆分或加载方式没有任何控制力。你不能靠它把 tailwind.css 单独拎出来,也不能让它延迟加载。
立即学习“前端免费学习笔记(深入)”;
- 想分离 Tailwind 或基础样式?必须用
@layer+content配置确保 JIT 编译精准,再配合动态导入触发拆分 - 想提取公共 CSS?只能靠组件级复用 + 动态导入路径收敛(比如所有报表页都从
pages/reports/下导入),让 Rollup 自动聚合成一个 chunk -
assetFileNames可以重命名 CSS 文件(如assets/css/[name].[hash].css),但不改变加载行为
真正有效的 CSS 加载优化组合
单页应用中,CSS 加载速度提升依赖三件事协同:拆分、压缩、加载时机。光靠 Vite 配置不够,得动手改代码结构。
- 开启
cssCodeSplit: true(保持默认即可,不用显式写) - 关闭
build.minify: 'esbuild'或改用'terser'—— esbuild 压缩会把小 CSS 内联进 JS,破坏拆分效果 - 用
vite-plugin-compression输出.gz和.br,服务端需支持 Brotli - 关键 CSS 提前内联(用插件如
vite-plugin-critical-css),非关键样式靠动态导入带出 - 检查
index.html中是否残留了旧的<link href="/style.css">—— 这类手动引入会阻塞渲染,且无法被 Vite 管理
最易被忽略的一点:CSS 是否“可拆分”,取决于它是否被动态导入链捕获。静态 import 的样式永远进主包,哪怕体积再小。别指望配置能绕过这个限制。


















