【原创】从零开始搭建Electron+Vue+Webpack项目框架(六)Electron打包,同时构建客户端和web端
导航:
(一)Electron跑起来
(二)从零搭建Vue全家桶+webpack项目框架
(三)Electron+Vue+Webpack,联合调试整个项目
(四)Electron配置润色
(五)预加载及自动更新
(六)构建、发布整个项目(包括client和web)
摘要:整个项目就剩最后一哆嗦了,但仅仅是当作demo模版来说,实际项目的话,还有很多需要细化的地方。项目完整代码:https://github.com/luohao8023/electron-vue-template,随博客更新。
一、打包客户端
首先是要改一下build.js,把上篇文章没做的事儿给做了。
上篇文章已经构建出了可执行文件目录app,这次我们要做的就是使用electron-builder把app目录打包为安装包。
在之前的基础上引入electron-builder,然后对app目录进行打包:
const builder = require('electron-builder'); // 在所有的打包逻辑执行完成之后,确认已经正确生成了app目录 builder.build().then(() => { del(['./pack/*.yaml', './pack/*.blockmap']); // 为了方便,打包完成之后我们打开文件管理器 openFileManager(); }); function openFileManager() { // 打开文件管理器 let dirPath = path.join(__dirname, '..', 'pack'); if (process.platform === 'darwin') { spawn('open', [dirPath]); } else if (process.platform === 'win32') { spawn('explorer', [dirPath]); } else if (process.platform === 'linux') { spawn('nautilus', [dirPath]); } }
然后自信满满的开始打包。。。。
报错了,说是什么描述缺失,icon没有设置啥的,就是打包的时候没有配置呗,去看下package.json文件,果然是少了build字段,package.json文件中的build字段就是有关打包的配置,一些必要的配置项还是要填的。
在package.json中增加build字段:
"build": { "asar": true, "productName": "Electron+vue+webpack模板", "appId": "com.electron.template", "copyright": "Copyright © template", "directories": { "output": "pack" }, "files": [ "app/**" ], "mac": { "identity": "com.electron.templat", "target": [ "dmg" ], "artifactName": "${productName}.${ext}", "icon": "main/favicon/favicon.icns" }, "dmg": { "title": "${productName}", "artifactName": "${productName}.${ext}", "icon": "main/favicon/favicon.icns" }, "win": { "legalTrademarks": "Copyright © template", "publisherName": "electron", "requestedExecutionLevel": "highestAvailable", "target": [ { "target": "nsis", "arch": [ "ia32" ] } ], "artifactName": "${productName}.${ext}", "icon": "main/favicon/favicon.ico" }, "nsis": { "oneClick": false, "allowToChangeInstallationDirectory": true, "perMachine": true, "allowElevation": true, "artifactName": "${productName}-安装包-V${version}.${ext}", "runAfterFinish": true, "shortcutName": "Electron+vue+webpack-template" } },
现在我们来挨个解读一下各个配置项都是什么意思,当然还有很多其他配置,这里不再额外介绍了。
asar:是否打包为asar文件,设置为true的话,相当于给你的代码加密了一下,直接就是个.asar的文件,具体内容需要解密了之后才能看到;设置为false的话,不对你的代码进行加密处理,也就是用户安装你的程序之后,找到安装目录,就能直接看到源码,目录结构跟你开发的时候是一样的,不太安全,建议设置为true;
(node:96470) UnhandledPromiseRejectionWarning: Error: Application entry file "index.js" in the "/Volumes/SHARE/projects/github/electron-vue-template/pack/mac/Electron+vue+webpack模板.app/Contents/Resources/app.asar" does not exist. Seems like a wrong configuration.
还是有错啊,说的很详细,说是程序入口文件index.js不存在,我们看一下:
"name": "electron-vue-template", "version": "1.0.0", "description": "electron-vue-template", "main": "index.js", "scripts": { "dev": "node ./builder/dev.js", "build": "node ./builder/build.js" },
main字段就是程序入口,我们写的是index.js,看下代码目录,我们的主进程入口是main.js,那就改一下吧,把index.js改为main.js,接着运行打包命令:
还是出错呦,入口文件找不到,这个问题还真想来好大一会儿,感觉没有错啊,名称也修改来,就是main.js啊,又瞅了眼代码目录才恍然大悟,这不阴沟里翻船嘛,通常情况下main.js是在工程根目录的,但是我们规划完工程目录之后,把main.js给打包到app目录下了,所以入口字段应该填"app/main.js",接着运行打包命令,这次终于成功了,看下pack文件夹中生成的文件:
第一个dmg文件就是mac的安装包,第二个yml文件记录了程序的一些基本信息,mac文件夹下是一个免安装的可执行程序,最后一个就是我们压缩出来的小版本,windows下跟这个目录不一样。
先不着急安装,打开mac文件夹下的可执行程序,可以直接打开我们的程序,打开之后懵了,一片空白啊,啥东西也没有,赶紧找找原因。
打开app目录发现,没有生成update.html,经排查发现,上次提交的代码有个地方写错了,拼错了个单词:
Promise.all([buildPreload(), buildRender()]).then(resolve => { resolve.forEach(log => { console.log('打包输出===>', log); }); const outpath = path.join(__dirname, '../pack/'); try { fs.mkdirSync(outpath); } catch(e) { console.log('已创建pack文件夹', e); } console.log('打包渲染进程完毕!压缩小版本!'); const zipPath = renderConfig.output.path; const fileName = setup.versionType + '-' + setup.version.join('.'); const filePath = path.join(zipPath, `../pack/${fileName}.zip`); compress(zipPath, filePath, 7 , (type,msg) => { if (type === 'error'){ Promise.reject('压缩文件时出错:' + msg); } else { console.log(`压缩包大小为:${(msg / 1024 / 1024).toFixed(2)}MB`); } }); Promise.all([buildMain(), buildUpdate()]).then(resplve => { resolve.forEach(log => { console.log('打包输出===>', log) }); builder.build().then(() => { del(['./pack/*.yaml', './pack/*.blockmap']); openFileManager(); }); }).catch(err => { console.error('打包【main】-【update】错误输出===>', err); process.exit(2); }); }).catch(err => { console.error('打包【preload】-【render】出错,输出===>', err); process.exit(1); });
看一下,第二个Promise.all.then中,参数写成了resplve,而在打印log的时候用的是resolve,偏偏上面有resovle,所以也没报错,但是第二次promise的log就全被吃了,赶紧改回来,再跑一下,果然有个错误:
打包输出===> ModuleNotFoundError: Module not found: Error: Can't resolve 'css-loader' in '/Volumes/SHARE/projects/github/electron-vue-template':undefined
没有css-loader,那就装一个:
打包输出===> ModuleNotFoundError: Module not found: Error: Can't resolve 'less-loader' in '/Volumes/SHARE/projects/github/electron-vue-template':undefined
又说没有less-loader,再装一个,运行命令,看到app目录下生成了update.html,这下应该没问题了吧。
打开mac文件夹下的免安装文件,程序启动后跟我们本地调试的效果是一样的,再使用安装包安装一下,安装完成打开后也是正常的。
好啦,打包客户端就说到这儿了,下面说一下怎么使用同一套代码打包web端。
二、打包web端
这里建议把打包web端的逻辑单独拆出来,网站代码是同一套,但是打包逻辑是两套
dev的逻辑就是起个devServer返回html文件就行了,不再多说。
而打包的话是针对单页面的,只会生成一个html文件,如果相针对每个路由都生成一个html文件,这里提供下思路:
引入路由文件,遍历路由,拿到路径,针对每个路径,实例化一个HtmlWebpackPlugin,即可生成一个html文件:
webpackDevConfig.plugins.push(new HtmlWebpackPlugin({ template: './src/index.ejs', filename: `.${routerPah}`, title: "加载中...", inject: false, hash: true, minify: false, cache: false }))
在package.js中增加启动命令:
"scripts": { "dev": "node ./buildClient/dev.js", "devweb": "node ./buildWeb/dev.js", "build": "node ./buildClient/build.js", "buildweb": "node ./buildWeb/build.js" }
分别调试和打包客户端、web端。
这篇文章端内容就到这里了,具体的逻辑还是要去看代码的。针对这套逻辑我们其实有已经上线了的产品的,很多细化的东西也有,但是不便拿出来说,也不好做成demo。模板中可能会有些冗余代码,就是之前的逻辑没有删除干净,自行优化就好了。
有什么问题欢迎留言讨论。项目完整代码:https://github.com/luohao8023/electron-vue-template。