JS 美化 / 压缩

按括号缩进美化,压缩时保护字符串不被破坏

JS 美化与"压缩"的边界:为什么不该用它替代真正的压缩器

美化做什么

美化(beautify)按括号层级重新缩进,把压缩成一行的代码展开成可读形式。它只改空白,不改变 token 序列,所以是安全的(前提是原代码本身没有依赖自动分号插入的边界问题,见下)。常见用途:

  • 读懂打包产物里的一段逻辑(会带上压扁的变量名,但结构可辨)。
  • 整理从压缩文件或日志里复制出来的片段。
  • 在提交前统一格式。

"压缩"在这里的边界

需要注意:本工具提供的是基于空白处理的压缩,不是terser、esbuild 那一类真正的压缩器。两者能力差异很大:

能力本工具(空白压缩)专业压缩器
删除多余空白与换行支持支持
删除注释谨慎处理支持(可配置保留许可注释)
变量名缩短(mangle)不支持支持,通常能减少 30% 以上
死代码消除不支持支持
语法级安全保证无基于 AST 解析,保证语义等价
生成 source map不支持支持

关键差异在最后两行。专业压缩器把代码解析成 AST(抽象语法树)再输出,它在语法层面知道哪些空白可以删;而基于文本的压缩必须靠启发式规则猜测。

所以结论明确:生产环境的代码压缩应该用 terser、esbuild、swc 这类工具(打包器通常内置),它们更快、更彻底、并且有 source map 支持。本工具的价值在于快速处理小片段、临时预览效果,不适合作为构建环节。

自动分号插入(ASI)相关的风险

JavaScript 有"自动分号插入"机制:某些换行处会被解释成语句结束。这带来几个经典陷阱,也是文本级压缩最容易出错的地方:

写法问题
return
value;
被解析成 return;,函数返回 undefined(换行被插入分号)
同一行 return value;正确
以 ( 或 [ 开头的下一行会被当作上一行的调用或下标继续,导致语义完全不同
以 + 或 - 开头被当作上一行表达式的延续

这些规则意味着把换行删掉并不总是安全:合并两行可能改变语义。正确的压缩实现会保留必要的换行或在语句末尾补分号;基于文本的实现在遇到这类边界时需要格外谨慎。手工压缩后如果行为变了,先怀疑这里的换行。

所以工具在压缩时会保护字符串与模板字面量的内容不被破坏——"a ; b" 里的分号、模板字符串里的换行都不能动。但即便如此,请把压缩结果当作"体积参考",不要直接用于生产。

格式化的其他注意点

  • 正则字面量与除号歧义。/ 既可能是除法也可能是正则的开始,判断依据是上下文。基于文本的实现容易被含有正则的代码绕晕,出现错误缩进。
  • 模板字符串里的换行必须保留。反引号内的内容是有意义的多行文本,重新缩进会改变字符串的值。
  • 现代语法。可选链 ?.、空值合并 ??、解构、装饰器等语法对基于文本的处理器也是考验——它们不是简单的括号嵌套。
  • 格式化不检查错误。它不会告诉你代码有语法错误,也不会补上缺失的分号或括号。想验证代码能不能运行,用运行类的工具或直接执行。

工具怎么用

粘贴代码,点美化得到缩进版本,或点压缩得到紧凑版本。适合快速整理片段、观察压缩后的体积量级。处理在浏览器本地完成,代码不会被上传——涉及内部业务逻辑时这一点很重要。

要作为构建环节使用,请改用专门的压缩器并启用 source map,这样线上报错仍能映射回源码位置。

常见问题

压缩会去掉注释和换行吗?

会,并尽量合并多余空白,但只在与前后标识符之间仍需分隔时才保留一个空格,保证语法正确。

为什么不用现成压缩工具那么激进?

本工具纯浏览器运行、零依赖,目标是"安全不报错",不会做变量重命名等可能改变作用域的激进优化。