【原創】從零開始搭建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;
productName:你的應用名稱,比如會顯示在安裝程式的標題處,以及安裝完成後的應用程式目錄裡; appId:你程式的唯一id,比如繫結到某第三方平臺或應用市場,一般會需要這個,我是沒有,隨便填的; copyright:按照網站的copyright來理解就好啦,如果你的程式不需要發不到各大市場的話,這個內容可以忽略; directories:它下面還有其他屬性,這裡我們只填了ouptut選項,就是打包輸出目錄,我們這裡填了pack資料夾; files:需要打包哪些內容,就是你的原始碼,我們這裡填的"app/*",就是app目錄下的所有內容; 上面都是一些基礎的內容,下面介紹一下針對不同平臺的配置: mac: identity:這個我不是特別清楚,看名字應該是表明開發者或者軟體身份的東西; target:你要打包成什麼格式的安裝包,這裡填的是dmg,可以填多個; artifactName:生成的可執行檔案的名稱; icon:應用圖示,顯示在桌面快捷方式或者系統托盤; 針對dmg的單獨配置這裡就不說了,因為mac選項的target屬性可以多填,我們填了dmg,就對dmg做了單獨的配置,也可以忽略; win: legalTrademarks:合法商標。。。。。。 publisherName:發行商類似的意思; requestedExecutionLevel:應用程式需要的許可權,我們這裡填的是highestAvailable,就是當前使用者允許的最高許可權,你如果是管理員使用者在使用,那就是管理員許可權,如果是普通使用者在使用那就是普通管理員許可權。設定為最高許可權可以解決一些問題,比如對c盤的一些檔案進行操作等。但是請注意一點,如果你的程式是以管理員身份執行的,但是你又想實現從桌面往應用程式中拖動檔案的功能,這是不行的,因為檔案管理器的許可權是低於管理員的,windows上無法從低許可權處往高許可權處拖動檔案,這點還是要注意一下; target:目標平臺,我們選32位,並且使用nsis打包; artifactName:可執行檔名稱; icon:應用圖示; nsis: 因為electron-builder是基於nsis打包的(有興趣的可以瞭解一下nsis),所以這裡提供了一些基礎配置: oneClick:不是點選一次,也不是單例什麼的,這裡是一鍵安裝的意思,設定為true的話,只要雙擊開啟安裝包,程式會自動安裝並執行;建議設定為false,讓使用者點選下一步、下一步來安裝; allowToChangeInstallationDirectory:是否允許修改安裝目錄,預設為false; perMachine:每臺機器是否只允許安裝一個程式,如果已安裝,再次安裝的時候,會要求使用者先刪除之前的程式; allowElevation:允許請求提升(許可權),如果設定為false,使用者必須重啟程式才能安裝提升了許可權的安裝程式; artifactName:安裝包名稱; runAfterFinish:安裝完成是否執行程式; shortcutName:快捷方式名稱 這是模版裡用到的所有屬性,解釋的也不一定對。當然還有很多其他的配置項,感興趣的可以搜一下了解了解,說不定某個小小的配置就能解決你一個大問題呢。 好了,說了這麼多,現在接著執行打包命令吧,看看啥情況:(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。