Vite默认cssCodeSplit: true仅物理拆分CSS文件,不改变加载时机,所有CSS仍同步插入HTML头部,首屏全量加载且可能重复打包;真正减少首屏体积需关闭自动分割、合并关键CSS并内联。

为什么默认 CSS 分割不一定减少首屏体积
Vite 默认开启 cssCodeSplit: true,会把每个异步 chunk 的 CSS 单独抽成 .css 文件。但问题在于:这些 CSS 文件仍会被同步加载(尤其在 SSR 或 preload 场景下),且可能重复打包相同样式规则。比如多个路由组件都 import 了同一套 UI 库的 Sass 变量,结果生成 3 个含重复 @import 的 CSS chunk,反而增加 HTTP 请求数和解析开销。
关闭无意义的 CSS 分割 + 合并核心样式
真正影响首屏的是「关键 CSS」是否内联或提前加载。对非关键路径的 CSS,分割反而拖慢;对关键路径,应合并压缩后内联。操作上分两步:
- 显式关闭自动 CSS 分割:
cssCodeSplit: false,让所有样式打到一个style.css中,避免碎片化 - 用
preprocessorOptions统一注入变量和混入,防止业务组件各自@import引入重复基础样式 - 若使用 PostCSS,确保
autoprefixer和cssnano插件启用,压缩后体积可降 30%+
示例配置片段:
export default defineConfig({
css: {
cssCodeSplit: false,
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss"; @import "@/styles/mixins.scss";`
}
}
}
})
按需提取关键 CSS 并内联到 HTML
首屏渲染必须的 CSS(如重置样式、布局容器、按钮基础类)不应走外链请求。Vite 本身不内置 critical CSS 提取,但可通过插件实现:
-
vite-plugin-critical-css:构建时分析 HTML 模板中的,提取首屏 DOM 覆盖的样式规则,生成内联 - 搭配
html-minifier-terser压缩 HTML,避免内联样式引入空白字符膨胀 - 注意:该插件依赖准确的
index.html结构,若首屏内容由 JS 动态渲染(如 Vue Router 的),需配合预渲染插件(如vite-plugin-prerender)才能命中真实首屏节点
动态导入时如何避免 CSS 重复加载
Vue / React 中用 defineAsyncComponent 或 lazy() 加载组件时,若组件内部 import './xxx.scss',Vite 会为每个 chunk 单独生成 CSS,导致样式多次插入 。这不是 bug,是默认行为。
- 解决方案:把所有组件共用的样式提到
src/styles/global.css,并在main.ts中一次性 import - 禁用组件内样式 import,改用 CSS Modules 或 scoped style,确保样式作用域隔离且不触发额外 CSS chunk
- 如果必须保留组件级样式,可在
rollupOptions.output.manualChunks中强制将所有.scss/.css归入一个styleschunk,并设injectStyles: 'head'控制插入时机
容易被忽略的一点:CSS 的 contenthash 默认不参与文件名哈希计算,修改样式后浏览器可能缓存旧 CSS。需在构建配置中显式开启:build.rollupOptions.output.entryFileNames: '[name].[hash].js' 并确保 CSS 输出也带 hash(Vite 5+ 默认已支持,但老项目升级后常被遗忘)。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











