前端代码压缩工具--closesure compiler
closesure-compile:
用来压缩加密js代码的工具
一个典型的简单用例:
使用指令:
java -jar closure-compiler-v20171023.jar --js test-closesure.js --js_output_file min.js --compilation_level ADVANCED_OPTIMIZATIONS
初始版本:
function sayHello(name) {
alert("Hello " + name);
}
sayHello('zhangsan');
sayHello('lisi');
class Student {
constructor(name, age) {
this.info = {};
this.info.name = name;
this.info.age = age;
}
sayName() {
alert(this.info.name);
}
}
// var stu = new Student('wangxiaoya', 29);
// stu.sayName();
代码体积:373 字节
压缩后45字节,内容如下:
alert("Hello zhangsan");alert("Hello lisi");
可以看到压缩时,删除空格换行,移除无用代码(class Student),简化函数(sayHello)
如果添加如下代码:
var stu1 = new Student('wangxiaoya', 29);
stu1.sayName();
var stu2 = new Student('gebaini', 29);
stu2.sayName();
var stu3 = new Student('wangzhi', 29);
stu3.sayName();
压缩之后:
function a(b){this.a={};this.a.name=b;this.a.b=29}alert((new a("wangxiaoya")).a.name);alert((new a("gebaini")).a.name);alert((new a("wangzhi")).a.name);
1.函数的参数名将发生变化
2.类中的属性名称可能被加密
2.如果由于所有人使用一样的age,则不会被传入,而是直接使用29
修改下代码:
var stu1 = new Student('wangxiaoya', 20);
stu1.sayName();
var stu2 = new Student('gebaini', 19);
stu2.sayName();
var stu3 = new Student('wangzhi', 29);
stu3.sayName();
stu3.sayAge();
压缩后:
function a(c,d){this.a={};this.a.name=c;this.a.b=d}alert((new a("wangxiaoya",20)).a.name);alert((new a("gebaini",19)).a.name);var b=new a("wangzhi",29);alert(b.a.name);alert(b.a.b);
这次参数被传入,不过属性名依旧被加密
使用注意事项:
1.尽可能不要使用eval
在上例中,使用eval,加密后代码崩掉,原因是编译器不会替换eval中的引用
eval("var stu4 = new Student('liqin', 20);stu4.sayName();");
加密后:
eval("var stu4 = new Student('liqin', 20);stu4.sayName();");
2.注意类的方法和属性可能被省略和重命名,因此暴露给用户的属性尤其需要注意这一点
var stu2 = new Student('gebaini', 19);
stu2.sayName();
alert(stu2.info.age);
加密后:
var b=new a("gebaini",19);alert(b.a.name);alert(b.a.b);
类名不要用字符串定义属性
class Student {
constructor(name, age) {
this.info = {};
this.info.name = name;
this.info['age'] = age;
}
var stu2 = new Student('gebaini', 19);
stu2.sayName();
alert(stu2.info['age'])
由于两处不一致,加密后出错
function a(d, e) {
this.a = {};
this.a.name = d;
this.a.age = e
}
var b = new a("gebaini", 19); alert(b.a.name); alert(b.a.b);
3.全局变量需要加window或者就都不要加
window.aa = {
'name': 'zhangsan',
'age': 20,
'address': 'xian',
'hobby': 'swim',
}
alert(window.aa);
变成:
window.a={name:"zhangsan",age:20,address:"xian",hobby:"swim"};alert(window.a);
或者
var aa = {
'name': 'zhangsan',
'age': 20,
'address': 'xian',
'hobby': 'swim',
}
alert(aa);
变成:
alert({name:"zhangsan",age:20,address:"xian",hobby:"swim"});
如果使用不一致,则错误
var aa = {
'name': 'zhangsan',
'age': 20,
'address': 'xian',
'hobby': 'swim',
}
alert(window.aa);
变成:
alert(window.a);
4.在除了constructor prototype外的方法使用this
var foo = {};
foo.bar = function (a) { this.bad = a; };
foo.bar("hello");
var foo$bar = function (a) { this.bad = a; };
foo$bar("hello");
5.两个静态方法重名
class A {
/** @nocollapse */
static create() {
return new A();
}
};
class B {
/** @nocollapse */
static create() {
return new B();
}
};
var ctor = new Date().getFullYear() > 2012 ? A : B;
ctor.create();
之后变成
function a(){}a.create=function(){return new a};function b(){}b.create=function(){return new b};(2012<(new Date).getFullYear()?a:b).create();
不加注释,两个方法都会被忽略
function a(){}function b(){}(2012<(new Date).getFullYear()?a:b).create();
6.使用三方库
如果压缩的文件使用了第三方的库,三方库不需要加密,那么只编译此文件会报错
var a = createDom();
var b = createDome();
document.append(a);
document.append(b);
test-closesure.js:58: ERROR - variable createDom is undeclared
var a = createDom();
^^^^^^^^^
test-closesure.js:59: ERROR - variable createDome is undeclared
var b = createDome();
^^^^^^^^^^
此时可以指定一个声明文件,告诉closesure,不需要更改此方法的名字,也不会报错
java -jar closure-compiler-v20181008.jar --js test-closesure.js --js_output_file min.js --compilation_level ADVANCED_OPTIMIZATIONS --externs aaa.js
声明文件aaa.js
function createDom(){
}