運用Electron+Vue3.2+TypeScript+Vite開發桌面端

語言: CN / TW / HK

Electron可以讓程式設計師重用Web的程式碼,使用HTML、CSS、JavaScript來構建桌面應用,並在不同平臺上使用。

Electron官網上說:“比你想象的更簡單”————“如果你可以建一個網站,你就可以建一個桌面應用程式。 Electron 是一個使用 JavaScript, HTML 和 CSS 等 Web 技術建立原生程式的框架,它負責比較難搞的部分,你只需把精力放在你的應用的核心上即可。”

Vue 是一套用於構建使用者介面的漸進式框架。與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。目前 Vue 已經成為繼 Rect 之後最流行的前端開發框架。

我找到了一個外掛:vite-plugin-electron,可以很方便的幫我們把 electron 和 vue 結合起來,開發起來非常方便。

目錄結構設計

因為我們需要使用 Electron 和 vue 進行開發,因此我們把它們分開目錄儲存,基礎目錄結構如下:

  • electron-main: 主程序目錄。
  • electron-preload: 預載入程式碼目錄,主要是定義橋接通訊。
  • 其他檔案: 也就是 vue 初始化後的目錄。

目錄結構這麼設計的原因是因為我們使用的 vite-plugin-electron 外掛需要使用這樣的目錄結構,目前還沒有提供設定修改。

初始化專案目錄

下面就開始初始專案:

yarn create vite electron-desktop --template vue-ts

先使用 vite 建立 vue 專案,然後我們再將 electron 嵌入到裡面。

初始化完成後,我們先做一個本地 yarn 源的配置,防止下載庫的時候出現異常。

配置.yarnrc

registry "https://registry.npm.taobao.org/"
electron_mirror "https://npm.taobao.org/mirrors/electron/"
electron_builder_binaries_mirror "http://npm.taobao.org/mirrors/electron-builder-binaries/"

配置完下載源後,就可以安裝 electron 了。

安裝Electron

yarn add -D electron electron-builder rimraf vite-plugin-electron electron-devtools-installer
  • electron-builder: 打包工具。
  • rimraf: 快速刪除檔案或目錄工具。
  • vite-plugin-electron: vite 結合 electron 的庫,關於這個外掛可以參見 Vite 與 Electron 無縫銜接。
  • electron-devtools-installer: electron 開發工具。

vite-plugin-electron 外掛是將 vite 和 electron 結合在一起的,可以讓我們非常方便的結合 electron 和 vue,需要做一些指定的配置。

初始化electron專案

可以參考 electron 官網的快速開始專案。

  • 建立主程序目錄和檔案。
// electron-main/index.ts
import { app, BrowserWindow } from 'electron';
import path from 'path';
const createWindow = () => {
  const win = new BrowserWindow({
    webPreferences: {
      contextIsolation: false,
      nodeIntegration: true,
      preload: path.join(__dirname, '../electron-preload/index.js'),
    },
  });
  if (app.isPackaged) {
    win.loadFile(path.join(__dirname, '../index.html'));
  } else {
    //  Use ['ENV_NAME'] avoid vite:define plugin
    const url = `http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`;

    win.loadURL(url);
  }
};
app.whenReady().then(() => {
  createWindow();
  app.on('activate', () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

需要注意引入的預載入檔案應該是打包後的 js 檔案,路徑和 ts 檔案路徑相同,只要型別改為 js 即可。

  • 建立預載入目錄和檔案。

在預載入檔案中我們列印一下系統平臺。

// electron-preload/index.ts
import os from 'os';
console.log(os.platform());

配置vite-electron

tsconfig.json

在 tsconfig.json 中監聽 electron 相關檔案和提示。

"include": [..., "electron-main/**/*.ts", "electron-preload/**/*.ts"],

vite.config.ts配置

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import * as path from 'path';
import electron from 'vite-plugin-electron';
import electronRenderer from 'vite-plugin-electron/renderer';
import polyfillExports from 'vite-plugin-electron/polyfill-exports';
export default defineConfig({
  plugins: [
    vue(),
    electron({
      main: {
        entry: 'electron-main/index.ts',
      },
      preload: {
        // Must be use absolute path, this is the limit of rollup
        input: path.join(__dirname, './electron-preload/index.ts'),
      },
    }),
    electronRenderer(),
    polyfillExports(),
  ],
  build: {
    emptyOutDir: false, // 必須配置,否則electron相關檔案將不會生成build後的檔案
  },
});

配置主程序和預載入指令碼地址。

package.json配置

{
  "name": "electron-desktop",
  "private": true,
  "version": "1.0.0",
  "main": "dist/electron-main/index.js",
  "scripts": {
    "dev": "vite",
    "build": "rimraf dist && vite build && electron-builder"
  },
  "dependencies": {
    "vue": "^3.2.25"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^2.3.1",
    "electron": "^18.2.0",
    "electron-builder": "^23.0.3",
    "electron-devtools-installer": "^3.2.0",
    "rimraf": "^3.0.2",
    "typescript": "^4.5.4",
    "vite": "^2.9.5",
    "vite-plugin-electron": "^0.4.3",
    "vue-tsc": "^0.34.7"
  }
}

主要是增加入口檔案,因為 electron 還沒有原生支援 ts,因此目前還是必須載入 js 檔案,所以入口檔案我們配置為解析後的 js 檔案路徑:

dist/electron-main/index.js,然後修改執行指令碼,在 build 命令中增加 electron-builder 打包命令。

electron-builder打包配置

# package.json
{
    ......,
    "build": {
        "appId": "com.electron.desktop",
        "productName": "ElectronVueVite",
        "asar": true,
        "copyright": "Copyright © 2022 XingXingZaiXian",
        "directories": {
          "output": "release/${version}"
        },
        "files": [
          "dist"
        ],
        "mac": {
          "artifactName": "${productName}_${version}.${ext}",
          "target": [
            "dmg"
          ]
        },
        "win": {
          "target": [
            {
              "target": "nsis",
              "arch": [
                "x64"
              ]
            }
          ],
          "artifactName": "${productName}_${version}.${ext}"
        },
        "nsis": {
          "oneClick": false,
          "perMachine": false,
          "allowToChangeInstallationDirectory": true,
          "deleteAppDataOnUninstall": false
        }
      }
  }

electron-builder 的配置我們有一篇專門的文章介紹,這裡並沒有什麼特殊的配置,按照需求配置即可。

到這裡就配置好了所有的檔案,接下來我們執行開發命令看一看效果。

yarn run dev

然後我們執行打包命令看一看效果。

yarn run build

執行完後會生成兩個目錄:dist 和 release。

dist 目錄中生成的是前端打包檔案,release 中生成的是 electron 打包檔案,內容如下:

其中 win-uppacked 中生成的是無需安裝的執行檔案,將此目錄直接壓縮後就可以傳送給別人,解壓即可使用。ExectronVueVite_1.0.0.exe 檔案是安裝包,開啟會顯示安裝過程,執行完安裝過程後在系統的控制面板中的軟體列表中可以看到該軟體,也可以執行解除安裝。

開啟後就是正常的軟體介面。

我們建立好了專案結構,那麼在使用 Vue 開發 Electron 桌面應用的時候還有一個比較重要的知識點要了解,就是訊息通訊。在新版本的 electron 中,推薦使用上下文隔離方式進行內部程序通訊,electron 官網有很詳細的介紹和示例,這裡我們只介紹一種方式,其他的方式大家可以通過檢視官網示例來了解。

我們的示例是在 Vue 介面中顯示當前系統平臺。

註冊上下文隔離介面

在 electron-preload/index.ts 中新增如下程式碼:

import os from 'os';
import { contextBridge } from 'electron';
contextBridge.exposeInMainWorld('electronAPI', {
  platform: os.platform(),
});

編寫上下文隔離介面的typescript型別宣告

通過 electron 註冊的上下文隔離介面會新增給 window 物件,但是原始的 window 物件並不存在這些介面和屬性,ts 就會報錯,這時就需要我們為其編寫ts型別宣告檔案.d.ts。

// src/types/global.d.ts
export interface IElectronAPI {
  platform: string;
}
declare global {
  interface Window {
    electronAPI: IElectronAPI;
  }
}

在Vue中呼叫介面

我們在 App.vue 中呼叫window.electronAPI.platform 介面,把系統平臺資訊顯示在介面上。

// src/App.vue
<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import HelloWorld from './components/HelloWorld.vue';
const platform = window.electronAPI.platform;
</script>
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld :msg="`Hello Vue 3 + TypeScript + Vite in ${platform}`" />
</template>

執行完以上步驟後,執行專案看一下效果。