cssnano@5+是唯一兼容PostCSS 8+的版本,因v4导出对象而非函数,会报TypeError;必须按postcss-import→autoprefixer→cssnano顺序配置,且需显式禁用mergeLonghand、discardDuplicates等高风险选项。

cssnano@5+ 是唯一能用的版本,旧版直接报错
PostCSS 8+ 要求所有插件必须是函数,而 cssnano@4 导出的是配置对象,不是函数。运行时会抛出 TypeError: plugin is not a function。必须升级到 cssnano@5 或更高版本:npm install cssnano@latest --save-dev。升级后,require('cssnano') 直接返回函数,不再需要传 { preset: 'default' } —— v5+ 已默认启用安全预设。
压缩前必须跑 postcss-import,否则 @import 全丢
如果 cssnano 在 postcss-import 前执行,所有 @import "base.css" 都不会被展开,而是被当成无效语句跳过或注释处理,最终产出的 CSS 缺失依赖。正确顺序只能是:postcss-import → autoprefixer → cssnano。在 postcss.config.js 中写成:
module.exports = {
plugins: [
require('postcss-import'),
require('autoprefixer'),
require('cssnano')
]
}
注意:Sass/Less 编译输出必须是 --style=expanded(非压缩格式),否则嵌套结构可能被解析失败,导致 postcss-import 内联失败。
默认 preset 不安全,关键选项必须显式关掉
默认 preset 会启用 mergeLonghand、discardDuplicates、reduceIdents 等高风险优化,极易引发样式丢失或错乱。比如:
立即学习“前端免费学习笔记(深入)”;
-
.btn--primary和.btn.is-primary被合并后,JS 动态切换类名失效 -
--theme-color自定义属性被重命名或删掉,主题切换崩溃 -
margin-top: 10px; margin-bottom: 10px合成margin: 10px 0 10px,但 JS 读取marginTop返回0
应在 cssnano 配置中显式关闭:
require('cssnano')({
mergeLonghand: false,
discardDuplicates: false,
reduceIdents: false,
discardComments: { removeAll: true }
})
Webpack 里光装插件不注册,CSS 根本不压缩
css-minimizer-webpack-plugin 是 Webpack 5+ 官方推荐方案,但它默认不生效。即使 mode: "production",CSS 文件体积也不会变小。必须同时满足三个条件:
- 已安装
css-minimizer-webpack-plugin和mini-css-extract-plugin -
mini-css-extract-plugin已启用,把 CSS 提取为独立文件(否则插件无目标可压) - 在
optimization.minimizer中显式注册插件实例,并设sourcemap: true(否则 sourcemap 断掉)
最小可用配置示例:
new CssMinimizerPlugin({
minimizerOptions: {
preset: ['default', { discardComments: { removeAll: true } }]
},
parallel: true,
sourcemap: true
})
真正容易被忽略的不是“要不要压缩”,而是压缩是否覆盖了所有入口、是否绑定了 contenthash、以及 HTML 中的 <link href=""> 是否由 html-webpack-plugin 动态注入——漏掉任意一环,用户都可能缓存旧 CSS,改了样式却看不到。


















