HTML、CSS、JS 压缩需分层处理:HTML 用 html-minifier-terser 安全压缩,跳过 <pre> 等特殊标签;CSS 必须用 cssnano 解析后优化;JS 唯一推荐 terser,兼容新语法并支持 tree-shaking。
必须分层完成 HTML、CSS、JS 代码压缩,不能把它理解为“删空格就完事”。其中 HTML 应安全执行 whitespace collapse,而 CSS/JS 要由专业解析器重写;如果盲目手动删除,结构可能受损并产生 bug,还容易破坏模板字符串、正则字面量,或误去掉关键分号。
<pre>、<textarea> 以及内联脚本和样式移除无意义的换行与空白,构成了 HTML 压缩的本质;然而直接 replace(/s+/g, ' ') ,会连同 <pre> 内部的缩进一起删除,进而导致页面显示异常。真实项目还需要跳过 <script type="text/template">、<style> 块中的内容,因为其中可能包含 CSS 或 JS 语法,不能按照纯文本进行压缩。
html-minifier-terser(Node.js)最为稳妥,它默认会保留 <pre>、<textarea>、<script>(非 module)、<style> 内容而不进行压缩collapseWhitespace: true(合并连续空白)、removeComments: true(删注释)、minifyCSS: true(调用 cssnano 压缩内联 <style>)、minifyJS: true(调用 terser 压缩内联 <script>)removeScriptTypeAttributes 和 removeStyleLinkTypeAttributes 可以安全启用,因为在 HTML5 中, type="text/javascript" 与 type="text/css" 已经属于冗余内容cssnano 对于 calc() 以及自定义属性,只有这样处理才安全用 sed 's/s+//g' 或简单正则去空格,会让 calc(10px + 2em) 变成 calc(10px+2em)——部分老浏览器不认;更糟的是,--my-var: #fff; 被误删分号会导致整条声明失效。CSS 是有语法树的,必须 parse 后再生成。
cssnano(PostCSS 插件),它能够识别 @supports、嵌套结构及自定义属性作用域,同时默认开启 discardComments、mergeLonghand 等安全优化reduceTransforms和(3D transform 兼容性可能因此受损)的 normalizeWhitespace(可能干扰某些字体加载逻辑)css-loader)已经传入 sourceMap: true,否则代码压缩后将无法调试terser 是唯一建议采用的方案,uglify-js 无法支持可选链与空值合并对于 ES2020+ 语法(a?.b、a ?? b、import.meta),在 uglify-js 环境下会直接报错,或者生成无效代码。而 terser 除兼容之外,还可移除未使用函数(、折叠 IIFE,并保证操作安全treeShaking 内联常量,并默认使 license 注释得到保留(,这些操作需配合 ESM)output.comments: /license/i)。
立即学习“前端免费学习笔记(深入)”;
terser input.js -o output.min.js --compress --mangle
TerserPlugin 完成配置:terserOptions.compress.drop_console: true 可以删除 console.*,但不要在开发环境启用mangle.reserved:如果使用了 Vue、React 或 jQuery 插件,需要把 $、jQuery、Vue 加入白名单,否则压缩后的代码会在运行时报告 ReferenceError
压缩并不是体积越小越好。过度压缩(例如 terser 开启 unsafe 选项、cssnano 强制执行 mergeRules)会造成 JS 逻辑混乱,也可能使 CSS 选择器权重失常。交互、表单校验和动画在上线前都必须放到真实浏览器中验证,压缩后的内容尤其要检查 Safari 对 async/await 的兼容情况。