【原創】從零開始搭建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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM