動態

詳情 返回 返回

vue項目打包electron-將已有web項目打包為桌面端 - 動態 詳情

當你需要將一個vue項目打包成electron時,只需要正常的安裝electron依賴、electron-builder依賴,正常的配置好主進程、預加載腳本、渲染進程即可。

依賴安裝

這裏默認你已經寫好了一個vue項目,腳手架為vite,然後需要打包成electron
安裝electron

pnpm add -D electron

安裝electron打包依賴

pnpm install electron-builder -D

為了使項目和electron正常運行,需要先運行項目,使得其開發服務器的url可以正常訪問,然後再開啓electron去加載url。 此處需要安裝兩個庫:

pnpm install -D cross-env wait-on

cross-env:該庫讓開發者只需要注重環境變量的設置,而無需擔心平台設置
wait-on:等待資源,此處用來等待開發服務器的url,然後開啓electron
此處依賴準備完畢。

配置修改及運行

修改package.json

  "scripts": {
    "name": "snow-admin",
    "private": true,
    "version": "0.0.0",
    "type": "commonjs",
    "description": "snow-admin",
    "main": "./electron/main.js",
    "author": "wangfan",
    "license": "MIT",
    "dev": "vite",
    "electron:dev": "wait-on tcp:5173 && cross-env VITE_USER_NODE_ENV=development electron .",
  },
解釋:
author、description為必填項
"main": "./electron/main.js"為主進程加載路徑
"type": "commonjs"表示以commonjs運行
啓動npm run electron:dev的時候,打開端口為5173,VITE_USER_NODE_ENV環境為development,啓動electron .

在根目錄新建electron文件夾
image.png
main.js為主進程
preload.js為預加載腳本
修改main.js中的內容

const { app, BrowserWindow } = require("electron");
const path = require("path");
// const NODE_ENV = process.env.VITE_USER_NODE_ENV;

// 創建一個窗口-封裝
function createWindow() {
  // 創建一個窗口
  const win = new BrowserWindow({
    width: 800, // 窗口寬度
    height: 500, // 窗口高度
    autoHideMenuBar: true, // 隱藏默認菜單
    webPreferences: {
      preload: path.resolve(__dirname, "./preload.js") // 加載預加載腳本,絕對路徑
    }
  });

  // 以url方式打開
  win.loadURL("http://localhost:5173");
}

// 監聽app的ready事件
app.on("ready", () => {
  createWindow();
  // window所有窗口關閉時,並且不是蘋果系統,退出應用-管理窗口的生命週期
  app.on("window-all-closed", () => {
    if (process.platform !== "darwin") app.quit();
  });
});

// 應用被激活時,窗口數量為0,自動創建一個窗口-管理窗口的生命週期
app.on("activate", () => {
  if (BrowserWindow.getAllWindows().length === 0) createWindow();
});

這裏就是一個最基本的主進程邏輯,唯一不同的就是打開方式是以url方式打開,路徑為本地項目5173端口
修改預加載腳本preload.js中的內容

const { contextBridge } = require("electron");

const NODE_ENV = process.env.VITE_USER_NODE_ENV;
console.log("預加載腳本,運行環境", NODE_ENV, process);

contextBridge.exposeInMainWorld("myAPI", {
  mytext: "這是暴露的變量"
});

這一步是為了讓你知道electron成功運行了,當你項目啓動的時候,控制枱會輸出console.log打印語句process是隻有node端才能使用的字段,若瀏覽器成功輸出,説明你成功調用nodeAPI
然後先啓動你的vue項目

pnpm run dev

image.png
這裏我的端口是5173
然後啓動electron項目

pnpm run electron:dev

image.png
electron中成功打開vue項目,打開控制枱可以看到預加載腳本console.log成功輸出了,説明vue項目打包electron成功了。
至於vue項目如何與electron主進程通信,這個就是electron的基本知識了,這裏不細講。
通信的過程應該是這樣的:
vue項目(渲染進程) -> 預加載腳本(preload.js) -> 主進程(main.js)
vue項目中正常過的調用預加載腳本函數,然後預加載腳本發送事件到主進程,主進程監聽事件做邏輯處理
例如:vue項目中調用預加載腳本定義的myAPI.saveFile函數,然後主進程監聽事件

// vue項目
window.myAPI.saveFile(form.value.username);

// 預加載腳本preload.js
contextBridge.exposeInMainWorld("myAPI", {
  mytext: "這是暴露的變量",
  saveFile: data => {
    console.log("調用預加載腳本");
    ipcRenderer.send("file-save", data);
  },
});

// 主進程main.js
ipcMain.on("file-save", ()=> {});

項目打包

package.json中修改

 "scripts": {
    "dev": "vite",
    "electron:build": "cross-env VITE_USER_NODE_ENV=production electron-builder",
  },

這裏實際上是指定你的運行環境為production,然後執行electron-builder命令來打包electron
package.json中與scripts同級,electron-builde打包配置:

  "build": {
    "appId": "snow-admin",
    "productName": "electron-snow",
    "copyright": "Copyright © 2024",
    "mac": {
      "category": "public.app-category.utilities",
      "icon": "./logo.ico"
    },
    "win": {
      "icon": "./logo.ico",
      "target": [
        {
          "target": "nsis",
          "arch": [
            "x64"
          ]
        }
      ]
    },
    "nsis": {
      "oneClick": false,
      "perMachine": false,
      "allowToChangeInstallationDirectory": true,
      "createDesktopShortcut": true,
      "createStartMenuShortcut": true,
      "shortcutName": "sd-cashier"
    },
    "files": [
      "dist/**/*",
      "electron/**/*"
    ],
    "directories": {
      "buildResources": "assets",
      "output": "dist_electron"
    }
  },

配置註釋


"build": {  
  "appId": "your.id", // 應用的唯一ID  
  "productName": "YourProductName", // 安裝後生成的文件夾和快捷方式的名稱  
  "win": { 
      "icon": "./logo.ico", // 應用圖標
      "target": [
        {
          "target": "nsis", // 指定使用 NSIS 作為安裝程序格式
          "arch":  ["x64"] // 生成64位安裝包
        }
      ]
  },
  "nsis": {  
    "oneClick": false, // 是否一鍵安裝,如果為 false,則顯示安裝嚮導  
    "allowElevation": true, // 是否允許請求提升(以管理員身份運行)  
    "allowToChangeInstallationDirectory": true, // 是否允許用户更改安裝目錄  
    "createDesktopShortcut": true, // 是否在桌面上創建快捷方式  
    "createStartMenuShortcut": true, // 是否在開始菜單中創建快捷方式  
    "shortcutName": "YourAppName", // 快捷方式的名稱  
    "uninstallDisplayName": "Your App", // 卸載時顯示的名稱  
    "license": "path/to/license.txt", // 許可證文件的路徑  
    "installerIcon": "path/to/installer-icon.ico", // 安裝程序圖標的路徑  
    "uninstallerIcon": "path/to/uninstaller-icon.ico", // 卸載程序圖標的路徑  
    "installerHeaderIcon": "path/to/header-icon.ico", // 安裝嚮導頭部的圖標路徑  
    "installerSidebarIcon": "path/to/sidebar-icon.bmp", // 安裝嚮導側邊欄的圖標路徑(必須是 BMP 格式)  
    "runAfterFinish": true, // 安裝完成後是否運行應用  
    "perMachine": true, // 是否為所有用户安裝(而非僅當前用户)  
    "script": "path/to/custom-nsis-script.nsh", // 自定義 NSIS 腳本的路徑  
    "compression": "lzma", // 壓縮方式,可選值包括 'none', 'zip', 'lzma' 等  
    "artifactName": "${productName}-${version}-Setup.${ext}", // 自定義輸出文件的名稱  
  },  
}

打包線上web項目

跟啓動本地項目沒有什麼區別,由於我們將已有的web端項目打包,所以很難做到將vue項目完全遷移到electron中,最簡單的方法就是修改主進程中的win.loadURL("你的線上url");
具體是通過process.env.VITE_USER_NODE_ENV來區分你的運行環境,這裏做一個主進程的示例:

const NODE_ENV = process.env.VITE_USER_NODE_ENV;
// 創建一個窗口-封裝
function createWindow() {
  // 創建一個窗口
  const win = new BrowserWindow({
    width: 800, // 窗口寬度
    height: 500, // 窗口高度
    autoHideMenuBar: true, // 隱藏默認菜單
    webPreferences: {
      preload: path.resolve(__dirname, "./preload.js") // 加載預加載腳本,絕對路徑
    }
  });

  ipcMain.on("file-save", writeFile);

  if (NODE_ENV == "development") {
    win.loadURL("http://localhost:5173"); // 本地
  } else {
    win.loadURL("http://101.126.93.137:82"); // 線上
  }
}

// 監聽app的ready事件
app.on("ready", () => {
  createWindow();
  // window所有窗口關閉時,並且不是蘋果系統,退出應用-管理窗口的生命週期
  app.on("window-all-closed", () => {
    if (process.platform !== "darwin") app.quit();
  });
});

通過環境區分來判斷你打開的項目
線上和本地其實是一樣的,只要項目在electron中正常打開就都具備與主進程通信的能力。
其實你的vue項目是一個渲染進程,也就是web端運行的,而electron正好可以通過預加載腳本來讓渲染進程和主進程通信,也就是説只要你的項目正常打開,它就運行在渲染進程,它就具備與主進程通信的能力。

打包生產環境dist到electron本地啓動

需要先掌握上一節,《打包線上web項目》的基礎知識,篇章為上一篇的進階

由於electron使用win.loadURL來加載頁面會有CSP(內容安全策略風險),並且它引用的是線上鏈接,所以非常不安全。
我們可以將vite+vue生產環境的包打到electron來生成應用,這樣更安全,且不需要發佈線上版本,安裝即用。
首先你要先配置好你的啓動環境,在我們本地開發的時候,electron監聽的是本地url鏈接,若打包生產,則使用的是生產包資源(dist)

配置啓動環境

配置啓動環境,本地項目運行,一鍵啓動web端和electron端

先配置本地啓動,通過concurrently來同時啓動多個命令,通過cross-env來設置運行環境

pnpm add -D concurrently
pnpm install cross-env --save-dev
  "scripts": {
    "dev": "vite",
    "start": "concurrently \"pnpm run dev\" \"pnpm run electron:dev\"",
    "electron:dev": "cross-env VITE_USER_NODE_ENV=development electron .",
    "electron:build": "vite build --mode production && cross-env VITE_USER_NODE_ENV=production electron-builder",
    "build:dev": "vue-tsc && vite build --mode development",
    "build:prod": "vue-tsc && vite build --mode production"
  },

本地開發的時候使用pnpm run start來同時啓動pnpm run devpnpm run electron:dev兩條命令
pnpm run dev就是正常啓動本地vite項目
pnpm run electron:dev就是啓動electron項目,在啓動這條命令的時候,會通過cross-env來設置環境變量VITE_USER_NODE_ENV=development,主進程就可以通過VITE_USER_NODE_ENV來判斷當前運行的是哪個環境
在本地項目中,我們需要在vite.config.ts中設置啓動端口

    server: {
      port: 8080, // 設置端口號
      cors: true, // 允許跨域
      hmr: true, // 開啓熱更新
    },

主進程中就可以根據當前環境來判斷加載方式,若是開發環境就監聽本地的8080端口,若是生產環境則使用vite打包後的dise/index.html文件,這個是啓動入口
image.png
這樣做,你在本地開發的時候只需要運行pnpm run start命令,就會啓動本地項目以及electron,由於配置了hmr熱更新,修改頁面electron項目也會同步更新。

打包生產環境,electron嵌入生產環境生成應用

我們在主進程中做了判斷

if (process.env.VITE_USER_NODE_ENV == "development") {
    win.loadURL("http://localhost:8080");
  } else {
    win.loadFile(path.resolve(__dirname, "../dist/index.html"));
  }

若不是開發環境,則走生產環境,這裏electron加載的文件為vite打包後的dist/index.html文件,使用的本地資源進行打包。
image.png
package.json中我們配置了這麼一條命令:

"scripts": {
    "electron:build": "vite build --mode production && cross-env VITE_USER_NODE_ENV=production electron-builder",
  },

首先需要搞清楚一件事,有些script啓動命令使用單個&,有些使用兩個&
&:同時啓動多個命令
&&:依次啓動多個命令
這裏先啓動vite build --mode production打包生產環境,然後啓動cross-env VITE_USER_NODE_ENV=production electron-builder設置生產環境,並且使用electron-builder打包應用。
我們稍後再運行打包命令,先配置打包路徑
image.png
在主進程文件中配置預加載腳本的路徑
image.png
打包配置,這裏使用electron-builder進行打包,在package.json中配置,與scripts同級

  "build": {
    "appId": "snow-admin",
    "productName": "snow-admin",
    "copyright": "Copyright © 2024",
    "mac": {
      "category": "public.app-category.utilities",
      "icon": "./logo.ico"
    },
    "win": {
      "icon": "./logo.ico",
      "target": [
        {
          "target": "nsis",
          "arch": [
            "x64"
          ]
        }
      ]
    },
    "nsis": {
      "oneClick": false,
      "perMachine": false,
      "allowToChangeInstallationDirectory": true,
      "createDesktopShortcut": true,
      "createStartMenuShortcut": true,
      "shortcutName": "sd-cashier"
    },
    "files": [
      "dist/**/*",
      "electron/**/*"
    ],
    "directories": {
      "buildResources": "assets",
      "output": "dist_electron"
    }
  },

運行打包指令pnpm run develectron:build生成應用程序
image.png

打包後的幾種常見報錯

1、安裝應用後項目白屏
image.png
這種可能是vite打包資源沒有指定到正確路徑,檢查vite.config.ts文件中的base字段,將其改為'./'
vite官方文檔上有説明:vite-base
image.png

注意:這個適用於嵌入形式開發,如果你修改了路徑打包成electron後,再打包web端需要改回來

2、項目正常啓動,但是預加載腳本運行報錯
image.png
可能是預加載腳本資源路徑報錯導致,檢查你的文件位置,若主進程和預加載腳本處於同級目錄,這裏就不能用../preload.js
image.png
將其改為preload.js./preload.js即可

const win = new BrowserWindow({
    // 省略其它...
  
    webPreferences: {
      preload: path.resolve(__dirname, "preload.js") // 加載預加載腳本
    }
  });

在這種資源嵌入打包的場景下,很多時候資源加載報錯都是因為路徑引入的問題導致,出現這種問題一定要好好檢查一下各文件的所處位置和引入路徑。

user avatar _6901c0fb92647 頭像
點贊 1 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.