前言
由于Laya1.x的版本没有开源发布项目的源文件,也有可能本人的能力问题,没有找到此文件,因此本文主要针对的是Laya1.x版本,至于Laya2.x的版本,可以根据需要去修改.Laya目录下的publish.js来优化打包流程。
痛点
在游戏项目上线期间,会经常打包,每次打包都很费时间,特别对于配置不好的设备,情况更甚,对于我这种懒人来说,可谓难受至极,优化势在必行。
分析
打包过程中所处理的事情如下:
- 图片资源的压缩 (很耗时间)
- js文件的压缩混淆 (混淆程度低,代码阅读难度低)
- 拷贝前面两步的文件到到发布目录
很多时候,我们只是改了代码,并没有改动到UI、场景和图片资源,这时候,我们其实只要替换JS文件就够了,图片资源等资源可以不用重新发布,这样就可以节省90%以上的时间。
做法:场景、UI和图片资源如果发生了变化,先用Laya IDE发布一下项目,后续如果只是JS文件发生改变,其他文件没法有发生改变,就不用Laya IDE再发布项目,只需将bin目录下js文件压缩混淆后,替换掉之前发布目录下的js文件
目标
最终的目标是得到一个zip的压缩包,此压缩包需包含以下几点:
- 压缩包命名为:游戏名_日期_版本号
- 压缩包里面的JS文件是包含最新功能的文件,并且已经压缩混淆过(这里使用javascript-obfuscator压缩混淆)
过程
此优化功能被添加到基于node.js的yargs库写的脚手架工具上,目的是为了能更方便使用命令行命令。具体的yargs功能,这里就不多阐述了,有兴趣的朋友可以去研究。
这里使用到async.js的series方法,按顺序处理任务,并且会等上一个任务完成后,才会执行下一个任务
const exec = require('child_process').exec;
const date = require("silly-datetime");
const archiver = require('archiver');
const async = require("async");
const path = require("path");
const fs = require("fs");
module.exports = {
// 这里 这里假设yargs的主命令是minigame, 这个文件对应的命令行指令就是 minigame pack
command: 'pack',
desc: '',
builder: (curYargs) => {
},
handler: (argv) => {
const gameName = "xxx";
// 待加密的js文件的根路径
const willEncryptJS = "bin目录下的js文件的根路径";
const output = "游戏包发布的路径";
const today = date.format(new Date(), "YYYY-MM-DD");
// 第二个参数用来输入版本号, 完整的命令: minigame pack ${version}
const version = process.argv[3];
const gamePathName = `${gameName}_${today}_v${version}`;
const gameOutput = path.join(output, `${gamePathName}`);
async.series({
// 第一步:创建 游戏名称_日期_版本号的目录 gameOutput
one:function(done){
fs.mkdir(gameOutput, { recursive:true }, (err) => {
if (err) {
return console.error("====> error:", err);
}
console.log("one done");
done(null, "one");
});
},
// 第二步:将laya发布后的web里面的内容考到 gameOutput
two:function(done){
const source = path.join(output, "web");
fs.cp(source, gameOutput, { recursive: true }, (err) => {
if (err) {
console.error(err);
} else {
console.log("two done");
done(null, "two");
}
});
},
// 第三步:删除gameOutput/js/src文件夹
three:function(done){
const srcPath = path.resolve(gameOutput, "js/src");
fs.rm(srcPath, { recursive: true}, (err) => {
if (err) {
console.error(`remove src dir error: ${err}`)
} else {
console.log("three done");
done(null, "three");
}
});
},
// 第四步:加密bin/js/src的所有js文件,并且输出到gameOutput/js/src下
four:function(done){
const dst = path.resolve(gameOutput, "js/");
const cmdStr = `javascript-obfuscator ${willEncryptJS} --output ${dst}`;
exec(cmdStr, function (err, stdout, srderr) {
if (err) {
console.error("javascript-obfuscator error: ", srderr);
} else {
console.log("four done");
done(null, "four");
}
});
},
// 第五步:将gameOutput输出zip压缩包
five:function(done){
// 创建可写流来写入数据
const output = fs.createWriteStream(gameOutput + ".zip");// 将压缩包保存到当前项目的目录下
const archive = archiver('zip', {zlib: {level: 9}});// 设置压缩等级
// on
output.on('close', function() {
console.log("five done");
done(null, "five");
});
archive.on('error', function(err) {
console.error("five error: ", err);
});
// 建立管道连接
archive.pipe(output);
archive.directory(gameOutput, false);
// 完成压缩
archive.finalize();
}
},function(error, result){
console.log("result done");
if (error) {
console.error("====> result error: ", error);
} else {
console.log("====> result:", result);
}
})
}
}
完成上述代码,只要打开终端,输入minigame pack 1,就会输入最终的游戏zip包,假设游戏的名字就coc, 今天是2022年11月4日,输入上述指令后,最后会成coc_2022-11-04_v1.zip包
因此打包的时候,如果只是JS文件改变,这是只要输入minigame pack ${version},几秒钟就会生成最终压缩包,可以直接上线,工作效率非常感人