二。在网上找到了一个名为'jjencode'的js加密算法,这里贴出他的网站:https://www.sojson.com/jjencode.html,通过此算法对js加密后台代码如下图:
三。如果对webpack的插件机制不了解的,可以参考这篇文章:https://juejin.im/entry/5a4cb7906fb9a04500037399。我将插件命名为'JsEncodePlugin',源码如下:
// 1、js-encode-plugin.js 文件(webpack的js加密插件)
const fs = require('fs');//node的文件系统模块,用于读写及操作文件
const path = require('path');//node提供的一些用于处理文件路径的小工具
var chalk = require('chalk')//用于向控制台输出带颜色的问题提示
// 2、模块对外暴露的 js 函数
function JsEncodePlugin(pluginOptions) {
this.options = pluginOptions;
}
// 3、原型定义一个 apply 函数,并注入了 compiler 对象
JsEncodePlugin.prototype.apply = function (compiler) {
const _this = this;
// 4、挂载 webpack 事件钩子(这里挂载的是 after-emit 事件,在将内存中 assets 内容写到磁盘文件夹之后触发的webpack生命周期钩子)
compiler.plugin('after-emit', function (compilation, callback) {
// ... 内部进行自定义的编译操作
// 5、操作 compilation 对象的内部数据
console.log(chalk.cyan('\n jsencode start.\n'))
var filePath = path.resolve(__dirname, _this.options.assetsPath);//设置需要加密的js文件路径,_this.options.assetsPath为插件配置中传过来的需要加密的js文件路径
filterFile(filePath);
function filterFile(fp){
fs.readdir(fp, (err, files)=>{//读取该文件路径
if(err){
console.log(chalk.yellow(
'读取js文件夹异常:\n' +
err.message + '\n'
))
return;
}
files.forEach((filename)=>{//遍历该路径下所有文件
if(_this.options.jsReg.test(filename)){//利用正则匹配我们要加密的文件,_this.options.jsReg为插件中传过来的需要加密的js文件正则,用以筛选出我们需要加密的js文件。
var filedir = path.resolve(fp, filename);
fs.readFile(filedir, 'utf-8', (err, data)=>{//读取文件源码
if(err){
console.log(chalk.yellow(
'读取js文件异常:\n' +
err.message + '\n'
))
return;
}
//调用jjencode函数对源码进行jjencode加密,_this.options.global为插件配置中传过来的加密使用的全局变量名,将在jjencode函数中作为第一个参数传入
let result = jjencode(_this.options.global, data);
fs.writeFile(filedir, result, (err)=>{//将加密后的代码写回文件中
if(err){
console.log(chalk.yellow(
'写入加密后的js文件异常:\n' +
err.message + '\n'
))
return;
}
console.log(chalk.cyan(' jsencode complete.\n'))
})
})
}
})
})
}
//js加密函数
function jjencode( gv, text )
{
var r="";
var n;
var t;
var b=[ "___", "__$", "_$_", "_$$", "$__", "$_$", "$$_", "$$$", "$___", "$__$", "$_$_", "$_$$", "$$__", "$$_$", "$$$_", "$$$$", ];
var s = "";
for( var i = 0; i < text.length; i++ ){
n = text.charCodeAt( i );
if( n == 0x22 || n == 0x5c ){
s += "\\\\\\" + text.charAt( i ).toString(16);
}else if( (0x20 <= n && n <= 0x2f) || (0x3A <= n == 0x40) || ( 0x5b <= n && n <= 0x60 ) || ( 0x7b <= n && n <= 0x7f ) ){
s += text.charAt( i );
}else if( (0x30 <= n && n <= 0x39 ) || (0x61 <= n && n <= 0x66 ) ){
if( s ) r += "\"" + s +"\"+";
r += gv + "." + b[ n < 0x40 ? n - 0x30 : n - 0x57 ] + "+";
s="";
}else if( n == 0x6c ){ // 'l'
if( s ) r += "\"" + s + "\"+";
r += "(![]+\"\")[" + gv + "._$_]+";
s = "";
}else if( n == 0x6f ){ // 'o'
if( s ) r += "\"" + s + "\"+";
r += gv + "._$+";
s = "";
}else if( n == 0x74 ){ // 'u'
if( s ) r += "\"" + s + "\"+";
r += gv + ".__+";
s = "";
}else if( n == 0x75 ){ // 'u'
if( s ) r += "\"" + s + "\"+";
r += gv + "._+";
s = "";
}else if( n < 128 ){
if( s ) r += "\"" + s;
else r += "\"";
r += "\\\\\"+" + n.toString( 8 ).replace( /[0-7]/g, function(c){ return gv + "."+b[ c ]+"+" } );
s = "";
}else{
if( s ) r += "\"" + s;
else r += "\"";
r += "\\\\\"+" + gv + "._+" + n.toString(16).replace( /[0-9a-f]/gi, function(c){ return gv + "."+b[parseInt(c,16)]+"+"} );
s = "";
}
}
if( s ) r += "\"" + s + "\"+";
r =
gv + "=~[];" +
gv + "={___:++" + gv +",$$$$:(![]+\"\")["+gv+"],__$:++"+gv+",$_$_:(![]+\"\")["+gv+"],_$_:++"+
gv+",$_$$:({}+\"\")["+gv+"],$$_$:("+gv+"["+gv+"]+\"\")["+gv+"],_$$:++"+gv+",$$$_:(!\"\"+\"\")["+
gv+"],$__:++"+gv+",$_$:++"+gv+",$$__:({}+\"\")["+gv+"],$$_:++"+gv+",$$$:++"+gv+",$___:++"+gv+",$__$:++"+gv+"};"+
gv+".$_="+
"("+gv+".$_="+gv+"+\"\")["+gv+".$_$]+"+
"("+gv+"._$="+gv+".$_["+gv+".__$])+"+
"("+gv+".$$=("+gv+".$+\"\")["+gv+".__$])+"+
"((!"+gv+")+\"\")["+gv+"._$$]+"+
"("+gv+".__="+gv+".$_["+gv+".$$_])+"+
"("+gv+".$=(!\"\"+\"\")["+gv+".__$])+"+
"("+gv+"._=(!\"\"+\"\")["+gv+"._$_])+"+
gv+".$_["+gv+".$_$]+"+
gv+".__+"+
gv+"._$+"+
gv+".$;"+
gv+".$$="+
gv+".$+"+
"(!\"\"+\"\")["+gv+"._$$]+"+
gv+".__+"+
gv+"._+"+
gv+".$+"+
gv+".$$;"+
gv+".$=("+gv+".___)["+gv+".$_]["+gv+".$_];"+
gv+".$("+gv+".$("+gv+".$$+\"\\\"\"+" + r + "\"\\\"\")())();";
//console.log(r);
return r;
}
// 6、执行 callback 回调
callback();
});
};
// 暴露 js 函数
module.exports =JsEncodePlugin;
四。插件写好后我们要在webpack的配置文件webpack.prod.conf.js中引入该插件,该文件为生产环境中webpack的配置入口。它也依赖于webpack.base.conf.js、utils.js和config/index.js。当运行'npm run build'做线上环境打包时会执行该文件代码。我们可以注释掉其中UglifyJsPlugin插件了,因为UglifyJsPlugin插件压缩和加密的功能,我们开发的JsEncodePllugin插件都能实现并且做得更好。
五。引入我们开发的JsEncodePlugin插件后,运行'npm run build'做一个线上打包后,我们就可以查看加密后的文件了。