CSS Modules 增大打包体积主因是局部作用域误用和冗余 locals 注入;需显式使用 :global()、禁用无谓的 exportLocalsConvention,并配合 contenthash 和按需加载控制 CSS 产出。

为什么 css-loader 的 modules 配置会悄悄增大打包体积
开启 CSS Modules 后,Webpack 会为每个类名生成哈希后缀(如 .button_abc123),这本身不增体积;但若同时启用了 exportLocalsConvention: 'camelCase' 或自定义 getLocalIdent,可能触发额外字符串拼接逻辑,让 CSS 文件里塞进大量重复的局部作用域标识符。
更关键的是:CSS Modules 默认把所有 :global() 外的选择器都视为局部作用域 —— 即便你只写了 .header,它也会被重命名。如果项目中混用全局样式(比如第三方 UI 库的 class)又没用 :global() 包裹,构建时会意外生成一堆无用的局部映射,JS Bundle 里随之多出几十 KB 的 css-loader 运行时代码。
- 检查
css-loader配置,禁用modules.exportLocalsConvention,除非真需要驼峰导出 - 全局类必须显式包裹:
:global(.el-button) { ... },否则会被重命名 - 用
onlyLocals: true配合css-loader?modules&onlyLocals专用于 SSR 样式提取,避免在客户端打包时注入冗余 locals 对象
mini-css-extract-plugin 提取 CSS 时,chunkFilename 写错会导致重复加载
很多人设成 chunkFilename: '[name].css',结果发现首页加载了 main.css,点击路由又加载一遍同名 main.css —— 因为异步 chunk 的 name 和入口 chunk 冲突,插件无法区分,强行复用文件名,却没做内容去重。
根本问题在于 Webpack 的 chunk 分组逻辑:当多个异步模块引用同一份 CSS,且 chunkFilename 不带 contenthash,插件会为每个 chunk 单独输出一份 CSS 文件(哪怕内容完全一样),浏览器就真会发多次请求。
立即学习“前端免费学习笔记(深入)”;
- 务必使用
chunkFilename: '[name].[contenthash:8].css',让内容一致的 CSS 输出相同文件名 - 避免在
splitChunks.cacheGroups中对 CSS 单独配置name,否则会覆盖chunkFilename的 hash 行为 - 如果用了
runtimeChunk: 'single',确保 CSS 提取不和 runtime 混进同一个 chunk,否则热更新时 CSS 也会被强制刷新
PostCSS 插件顺序错乱会让 autoprefixer 白忙活
常见现象:开发时写 display: grid,浏览器能渲染,但打包后生成的 CSS 里没有加 -ms-grid 前缀,IE11 直接白屏 —— 不是 autoprefixer 失效,而是它运行时看到的 CSS 已被 postcss-preset-env 转译成现代语法,原始的 grid 早没了。
PostCSS 插件执行顺序是从左到右,autoprefixer 必须放在所有语法转换插件之后,否则它处理的是“转译后”的 CSS,不是源码。
- 正确顺序示例:
[postcss-preset-env, autoprefixer]→ 先降级语法,再补前缀 - 若用了
cssnano,它默认启用autoprefixer,此时要关掉自己的autoprefixer实例,避免重复运行和顺序冲突 - 检查
postcss.config.js是否被node_modules里的 preset 覆盖 —— 很多 UI 库自带 PostCSS 配置,会劫持你的插件链
未剔除未使用的 CSS(unused-css)比压缩更影响体积
Gzip 后 main.css 看似只有 120KB,但其中可能有 40KB 是从未在任何页面上渲染过的组件样式 —— 比如后台管理页的弹窗 CSS 被打进了前台首页的 CSS 包。Tree-shaking 对 CSS 无效,Webpack 不知道某个 class 字符串是否被 JS 引用过。
目前最稳妥的方式仍是手动控制:按路由或功能域拆分 CSS import,配合 mini-css-extract-plugin 的 chunk 分离能力。自动化方案(如 purgecss-webpack-plugin)容易误删动态生成的 class(className={styles[status]})或第三方库的 BEM 类名。
- 禁止在入口 JS 里
import './global.css',改用 HTML<link>或HtmlWebpackPlugin注入 - 组件级 CSS 只在对应组件内
import,不提升到 layout 或 store 层 - 若用 PurgeCSS,必须配置
whitelistPatterns: [/^ant-/]之类规则,否则 Ant Design 的.ant-btn-primary会被清掉
真正难的不是怎么删 CSS,是怎么让团队写代码时不自觉地“隔离样式作用域”——一旦 CSS import 出现在高阶组件或工具函数里,体积优化就变成一场持久战。










