uglify-js代码是如何被压缩的

# AST (抽象语法树)
抽象语法树:AST(Abstract Syntax Tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。树上的每个节点都表示源代码中的一种结构。之所以说语法是「抽象」的,是因为这里的语法并不会表示出真实语法中出现的每个细节。
举个例子
可以看出 AST 是源代码根据其语法结构,省略一些细节,抽象成树形表达。
tips: 具体的 AST 树大家可以在 astexplorer (opens new window) 上在线获得
# 代码压缩原理
- 将 code 转换成 AST
- 将 AST 进行优化,生成一个更小的 AST
- 将新生成的 AST 再转化成 code
babel,eslint,v8 的逻辑均与此类似,下图引用了 babel 的转化示意图

uglify 是怎么一步一步被压缩的?
// uglify-js的版本需要为2.x, 3.0之后uglifyjs不再暴露Compressor api
// 2.x的uglify不能自动解析es6,所以这里先切换成es5
// npm install uglify-js@2.x
var UglifyJS = require("uglify-js");
// 原始代码
var code = `var a;
var x = { b: 123 };
a = 123,
delete x`;
// 通过 UglifyJS 把代码解析为 AST
var ast = UglifyJS.parse(code);
ast.figure_out_scope();
// 转化为一颗更小的 AST 树
compressor = UglifyJS.Compressor();
ast = ast.transform(compressor);
// 再把 AST 转化为代码
code = ast.print_to_string();
// var a,x={b:123};a=123,delete x;
console.log("code", code);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
我们了解了 uglifyjs 的代码压缩原理,但是有个问题:为什么某些语句间的分号会被转换为逗号,某些不会转换? 这就涉及到 uglifyjs 的压缩规则
# 代码压缩规则
由于 uglify 的代码压缩规则很多,这里只分析与本文相关的部分 这其中需要注意的是只有“表达式语句”才能被合并,那么什么是表达式语句呢?
# 表达式 VS 语句 VS 表达式语句
// 表达式
a; //返回a的值
b + 3; // 返回b+3的结果
// 语句
if(x > 0) {
...
}
for(var i = 0;i < arr.length; i ++) {
...
}
const a = 123;
// 表达式语句
A();
function() {}();
delete x.b;
b = b + 3;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
综上所述,因为 a = 123 和 delete x 都是表达式语句,所以分号被转换为逗号。而 var x = {b:123}则因为是声明语句,所以和 a=123 不会合并,分号不会被转换。但 var x = {b:123}和第一行 var a 又触发了另外一条规则,所以第一行和第二行会被合并为 var a,x={b:123}
上次更新: 2021/12/14, 23:27:23