能保留特定注释,但必须绕开 cssnano default preset 并手动配置 discardcomments:default 内置 removeall: true 会无差别删除所有注释,需设 removeall: false 并用 regex 字符串匹配允许保留的注释开头(如 "@license|@theme|debug"),同时确保 css-loader 等前置工具未提前删注释。

能保留,但必须绕开默认 preset,手动配置 discardComments。cssnano 的 default 预设会无差别删除所有注释,想留特定内容(比如版权头、调试标记、关键业务说明),就得干预底层选项。
为什么 default preset 会删掉所有注释?
因为 default 内置了 discardComments: { removeAll: true } —— 这是安全保守策略,避免注释干扰压缩逻辑或暴露敏感信息。它不区分 /* copyright */ 和 /* DEBUG: toggle this */,一并清空。
常见错误现象:/* @license MIT */ 或 /* theme: dark-mode-only */ 在构建后消失,导致法律风险或样式失效。
- 使用场景:开源项目需保留 license 注释;内部系统要标记可调试区块;多主题 CSS 需靠注释识别生效条件
- 参数差异:不能只写
discardComments: false(无效),必须传对象,且removeAll和removeAllButFirst是互斥开关
怎么只保留特定注释?
用 discardComments 的正则白名单模式,匹配你允许保留的注释开头:
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
module.exports = {
plugins: [
require('cssnano')({
preset: ['default', {
discardComments: {
removeAllButFirst: false, // 关键:关掉“只留第一个”的捷径
removeAll: false, // 关键:关掉全删
// 只保留以 @license、@theme、DEBUG 开头的注释
regex: /^(@license|@theme|DEBUG)/
}
}]
})
]
}
注意:regex 是字符串正则,不是 RegExp 实例;/^\/\* @license/ 这类带斜杠的写法会失效,只写核心标识符即可。
- 容易踩的坑:误写
regex: /@license/→ cssnano 会报错,必须用字符串"@license"或"^(@license|DEBUG)" - 性能影响:正则匹配发生在每条注释上,但现代项目注释极少,几乎无感知
- 兼容性:该配置在 cssnano v6+ 稳定支持,v5 需升级
Webpack 用户特别注意 loader 冲突
如果你同时用了 css-loader,它的 minimize 选项默认开启(尤其 Webpack 4/5),会抢先压缩一次 CSS —— 导致 cssnano 收到的已是“半压缩”代码,注释早已被删光,你的 regex 完全没机会生效。
- 解决方法:在
css-loader配置中显式关掉它:{ loader: 'css-loader', options: { minimize: false } } - 验证方式:临时把
discardComments.regex设成"xxx",构建后检查输出里是否还有/* @license—— 没有就说明被 loader 截胡了 - 额外提醒:Vite 用户要在
vite.config.ts的css.postcss.plugins手动拼数组,不能依赖插件自动注入
真正难的不是写正则,而是确认注释从源码到最终产物的完整链路有没有被其他工具提前截断 —— 构建流程越长,越容易漏掉某一层的隐式压缩开关。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










