1. 程式人生 > >【原創】從零開始搭建Electron+Vue+Webpack專案框架(六)Electron打包,同時構建客戶端和web端

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