electron桌面端应用批量打包(electron 打包)
场景:
按产品需要,应用需要打多种马甲包(换个图标名字)及渠道包(同种包有不同的渠道),多达上百个,包名还需要根据渠道、版本、名称经过加密来命名。
打包过程:需要更换图片、渠道id、名字、版本号,然后运行打包命令,等待三四分钟编译打完包,然后更改加密后的包名
想象一下,几百个包,守在那里,一个一个打...
批量打包原理:
这里先是将需要打包的资源图片用统一的命名规范放在一个文件夹里面,然后用nodejs读取该文件就可以知道要打哪些马甲包,然后在遍历打包过程中用nodejs读取替换图片,计算加密包名,读取并更改配置文件,最后运行打包命令。说的可能不明不白,下面贴上代码:
创建channelMRD.js文件,代码如下:
引入fs模块,并读取目录确定所要打的包。所有要打包的图片资源都放在了文件夹resourcesImage里面。并过滤掉垃圾文件,防止后面遍历过程报错
const fs = require('fs'); const { mkdirpSync } = require('fs-extra'); const execSync = require('child_process').execSync; const images = fs.readdirSync('./resourcesImage').filter(item => item != '.DS_Sto复制代码
对images进行遍历操作
images.forEach(async (f, i) => { ... });复制代码
在遍历过程中替换图片,使用fs模块将resourcesImage下的图片资源替换到对应项目图片所在位置。
fs.copyFileSync(`./resourcesImage/${f}/${f}.ico`, `./resources/${f}/favicon.ico`); fs.copyFileSync( `./resourcesImage/${f}/${f}.ico`, `./resources/${f}/favicon-256.ico` ); fs.copyFileSync(`./resourcesImage/${f}/${f}.png`, `./resources/${f}/logo.png`); // 替换应用程序、程序坞、mac右上角图标 fs.copyFileSync(`./resourcesImage/${f}/icon_512.png`, `./icon.png`); fs.copyFileSync(`./resourcesImage/${f}/favicon_16.png`, `./script/favicon.png`); fs.copyFileSync(`./resourcesImage/${f}/favicon2_64.png`, `./script/favicon2.png`); fs.copyFileSync(`./resourcesImage/${f}/favicon2_64.png`, `./src/assets/icons/logo1024.png`); fs.copyFileSync(`./resourcesImage/${f}/favicon2_64.png`, `./src/assets/icons/logo.png`); fs.copyFileSync(`./resourcesImage/${f}/favicon2_64.png`, `./script/logo/favicon.png`);复制代码
设置配置文件。首先需要知道要设置成多少:resourcesImage图片命名按要求拼接好后,这里直接读取就可以了
const [ channel, folderName, shortcutName, version = '4.0.1', ] = f.split('-');复制代码
拿到配置,接下来设置配置文件即可,这里将设置配置文件的代码放到了新建的channelProcess.js文件里了,通过child_process模块运行该脚本即可
execSync( `node ./channelProcess.js ${folderName} ${shortcutName} ${channel} ${f} ${version} ${channel_type}` );复制代码
进入channelProcess.js,首先是获取传进来的配置信息:
const fs = require('fs'); const argv = process.argv; const name = argv[2]; const shortcutName = argv[3]; const channel = argv[4]; const fileName = argv[5]; const version = argv[6] || '1.0.0'; const channel_type = argv[7];复制代码
先是修改package.json配置,内容较多,可能有点麻烦
读取package.json并修改配置信息:名字、版本号、包名、id等
const readWriteFile = path => { fs.readFile(path, function (err, data) { if (err) { console.log(`read [${path}] error`); } else { const jsonData = JSON.parse(data.toString()); // 读取的package.json内容 const stringData = JSON.stringify(changeData(jsonData)); // 修改后的package.json内容 writeFile(path, stringData); // 写入package.json } }); }; readWriteFile('./package.json');复制代码
changeData:修改名称、版本、id等配置
const changeData = data => { data.name = name + `-mac` + `-c${channel}`; data.version = version; data.description = name + `-mac` + `-c${channel}`; data.build.appId = name + `-c${channel}` + `-mac`; data.build.productName = shortcutName; //应用程序桌面名字(mac) data.build.artifactName = artifactName + '.${ext}'; // '${productName}-${version}' + `-c${channel}` + '.${ext}'; data.build.nsis.shortcutName = shortcutName; data.build.directories = { output: `dist/c${channel}-${channel_type}` } return data; };复制代码
artifactName是经过md5加密的最终名称
const md5 = require('md5') //16进制转为10进制 function hex2int(hex) { var len = hex.length, a = new Array(len), code; for (var i = 0; i < len; i++) { code = hex.charCodeAt(i); if (48 <= code && code < 58) { code -= 48; } else { code = (code & 0xdf) - 65 + 10; } a[i] = code; } return a.reduce(function (acc, c) { acc = 16 * acc + c; return acc; }, 0); } //执行方法 function clickmd5(version, channel, channel_type){ const value = `v${version}_c${channel}_${channel_type}_mac_ltz` return "app_" + value.substring(0,value.length-3) + hex2int(md5(value).substring(4,8)); } // 得到最终名称 const artifactName = clickmd5(version, channel, channel_type)复制代码
writeFile:写入文件包一层
const writeFile = (path, data) => { try { fs.writeFile( path, data, { encoding: 'utf8', }, err => { if (err) throw err; console.log(`-- write [${path}] set success`); } ); } catch (error) { console.log(`write [${path}] error: `, error); } };复制代码
修改其他配置同理,甚至更简单,直接覆盖写入即可
// 更改配置文件./public/preload.js const publicPreloadText = `window.channelName='${shortcutName}';window.EXTEND_SOURCE='c${channel}';`; writeFile('./public/preload.js', publicPreloadText); // 更改配置文件./script/preset.js const scriptPresetText = `const channelName='${shortcutName}'; module.exports={channelName};`; writeFile('./script/preset.js', scriptPresetText); // 更改配置文件./src/utils/config.js const configText = `const PLATFORM = '4'; const CHANNEL_TYPE = '${channel_type}'; const VERSION = '${version}'; const PACKAGE = '${name}';const EXTEND_SOURCE = '${channel}';export{PLATFORM, CHANNEL_TYPE, VERSION,PACKAGE,EXTEND_SOURCE}`; writeFile('./src/utils/config.js', configText);复制代码
至此,配置文件更改完毕。回到channelMRD.js文件下的遍历操作那里,改完配置后就是开始打包了。这里需要注意的是直接运行execSync('yarn edist')打包后会有文件丢失,我当时为了查看控制台输出,加入配置{stdio: 'inherit'}后就正常了
execSync('yarn edist', {stdio: 'inherit'});复制代码
还有同一种马甲包下有不同渠道包,这里渠道比较简单,就1、2、3,遍历123执行步骤5跟步骤9即可
// channel_type 1-正常包 2-分享包 3-下载包 let channel_type = 1 while (channel_type <= 3) { execSync( `node ./channelProcess.js ${folderName} ${shortcutName} ${channel} ${f} ${version} ${channel_type}` ); execSync('yarn edist', {stdio: 'inherit'}); channel_type++ }复制代码
批量打包命令:在package.json的script下加入
"dist:all": "node ./channelMRD.js"复制代码
运行 yarn dist:all 坐等打包即可
总结:虽然过程看起来繁琐,其实就是用nodejs的fs模块读写文件,以及child_process模块execSync运行命令而已
作者:lnuyasha
链接:https://juejin.cn/post/7031458145969012743