使用electron+vue建立desktop app

2025/05/05

關於Electron

這個技術在多年前就聽過稍微瞄過一些文章

不過都還沒有實際動手去做過

最近剛好幫朋友規劃一套destktop app

於是就開始survey相關的技術

一開始初步看主流有python(PyQt) / C# / Java / js(electron) / dart(flutter)這幾種技術

初步選定的廠商分別使用兩種技術

分別是flutter跟electron

雖然現在業主還未決定發包的廠商

但因為我自己本身是寫web都是碰js

所以就針對electron去動手做一個基本的app去實測效能

然後也感受一下開發體驗跟學習曲線

 

Flutter vs Electron

會選這兩個主要是這在主流中算是熱門

而且重點是這兩個都是可產出跨平台desktop app

 

Flutter

除了desktop可產mac os/windows/linux/chrome os之外

也可以產mobile app包含andriod跟ios

然後web也行(不過初步看過很多人都說SEO不友善)

這部分真的很強學一套可以用好幾個地方

熱門的案例主要是mobile app為主: Grab / ebay / Toyota / BMW

 

優點

  • 上述說的學習、使用的效益高,可一次產出多種app
  • 因為最後是直接編譯成個平台的程式碼,所以效能佳

缺點

  • 學習曲線高
  • 相較於js(electron)生態系比較小

 

Electron

則是主打web可直接做成desktop app

也是目前滿熱門的desktop app開發工具

底層是啟動Chromium

所以才可以直接支援Web前端

滿多熱門的Desktop App像是Notion / Discord / Slack / VS Code / Claude / OpenAI / Figma / Postman都是用electron實作的

 

優點

  • 學習曲線低,只要會web前端+nodejs即可開發
  • 可直接用自己習慣的前端框架、UI framework非常方便
  • 生態系龐大有各種npm資源可用

缺點

  • 相較於Flutter只能產出Desktop app
  • 底層是用Chromium啟動,因此效能相對差,而且開越多新視窗消耗的效能越多(每個視窗都是新的Chromium instance)
  • 輸出檔案大
    • 單一檔案exe: 100-200MB起跳,好處是搬移方便,但是在windows上啟動速度較慢,約5-10秒
    • portable目錄類型(dir): 600MB起跳,好處在是啟動非常快速

 

Desktop app技術選型評估點

  • 效能要求: 一般小型應用可能還好,但是複雜一點的需求,或是像是開多個視窗electron效能表現會差很多(每個新視窗就是開一個Chromium實體)
  • 學習成本或是發案成本: electron成本相對低,如果本身就是寫web的更是一大優點
  • 是否要同時開發多種平台: 像是flutter連mobile app都可以做

 

開始透過electron-vite實作

electron-vite 是一個electron 開發/building工具

他有幾個優點包含

  • hot reload
  • 有vscode extension方便debug
  • 支援typescript
  • 開箱即用提供各種template像是vue/react/solid
  • assets資源已經直接幫你優化好,以及assets相關的路徑設定等等都不用自己處理

 

建立electron vue template

ref

pnpm create @quick-start/electron

這樣就可以直接建出一個template

稍微看一下package.json內的npm script

就可以發現做得很完整

輸出也可以針對不同作業系統個別輸出app

{
  "scripts": {
    "format": "prettier --write .",
    "lint": "eslint --cache .",
    "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
    "typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
    "typecheck": "npm run typecheck:node && npm run typecheck:web",
    "start": "electron-vite preview",
    "dev": "electron-vite dev",
    "build": "npm run typecheck && electron-vite build",
    "postinstall": "electron-builder install-app-deps",
    "build:unpack": "npm run build && electron-builder --dir",
    "build:win": "npm run build && electron-builder --win",
    "build:mac": "npm run build && electron-builder --mac",
    "build:linux": "npm run build && electron-builder --linux"
  },
}

 

接著就跟一般前端框架開發一樣

install package、run dev即可

馬上就會啟動一個desktop app

electron-vue-dev

 

electron IPC

ref

IPC就是UI前端跟原生API溝通的方式

以上方截圖來說

點擊Send IPC按鈕後

前端會觸發一個method透過electron ipcRenderer傳送訊號或資料

// src/renderer/src/App.vue
const ipcHandle = (): void => window.electron.ipcRenderer.send('ping')

 

在electron nodejs中

就可以收到前端的訊號或資料

做後續的處理或是操作原生API

// src/main/index.ts
import { app, shell, BrowserWindow, ipcMain } from 'electron'
ipcMain.on('ping', () => console.log('pong'))

 

build app(macOS)

pnpm build:mac

執行後就會立刻打包mac app

產出預設是可安裝檔dmg、以及portable app

都在dist目錄內

 

dmg安裝檔

  • 檔案大小: 327MB
  • 啟動時間: 第一次啟動約5秒, 第二次啟動約1-2秒速度快很多
  • RAM: 約180MB

electron-vue-build-macos-dmg

electron-vue-macos-dmg

 

portable app(在dist/mac-arm64目錄內)

  • 檔案大小: 907MB
  • 啟動時間: 約2-3秒
  • RAM: 約180MB,跟dmg安裝的類型差不多

electron-vue-single-app-performance

 

不過如果是要產單一portable app

可以調整一下electron-builder.yml內的mac設定

 

build app(windows)

因為我本身是在mac上開發

因此無法直接build windows app

需要靠docker環境

Dockerfile內用node:22-bullseye image

並且安裝一些wine相關套件

FROM --platform=linux/amd64 node:22-bullseye

RUN dpkg --add-architecture i386 && \
    apt-get update && \
    apt-get install -y \
        --no-install-recommends \
        wine \
        wine32 \
        libwine:i386 \
        libwine \
        fonts-wine

CMD tail -f /dev/null

 

docker-compose.yml的部分

可將一些cache目錄設定至local volumes加速

services:
  electron-vue:
    container_name: electron-vue
    image: electron-vue
    build:
      context: ./docker
      dockerfile: Dockerfile
    volumes:
      - .:/app
      - pnpm-store:/pnpm-store
      - electron-cache:/root/.cache/electron
      - electron-builder-cache:/root/.cache/electron-builder
    environment:
      - PNPM_STORE_PATH=/pnpm-store
    restart: unless-stopped
    tty: true

volumes:
  pnpm-store:
    driver: local
  electron-cache:
    driver: local
  electron-builder-cache:
    driver: local

 

設定完之後在container內

即可直接使用npm script build:win產生windows desktop app

至於產出的方式我這邊主要嘗試兩種

 

單一exe檔

electron-builder.yml的win.target加入portable選項即可輸出單一exe

另外可設定executableName讓輸出檔名固定

win:
  target:
    - portable
  executableName: electron-vue
  • 大小: 225MB
  • RAM: 200MB
  • 啟動時間: 10秒(這點真的很久)

 

portable目錄(dir)

electron-builder.yml的win.target加入dir即可

win:
  target:
    - dir
  • 大小: 1GB
  • RAM: 180MB
  • 啟動時間: 1秒

 

image

 

輸出類型選擇

以上macOS跟windows比較完可以看到

很明顯不管在哪種作業系統只要輸出單一檔案就會啟動比較慢

windows上會很明顯的更慢

這部分就要看實際應用的需求來決定輸出類型

 

Gitlab CI自動產出windows desktop app存到job artifact中

以下是target dir mode(portable app)範例

我把前面的Dockerfile建成一個專用的image ciaochung/electron-dev-windows:x64-node22

在Gitlab CI中直接使用不用每次一直重複安裝套件

完成後直接把整個desktop app目錄存到job artifact中可供下載

stages:
  - build

variables:
  APP_FOLDER: $CI_PROJECT_DIR/electron-vue

cache:
  paths:
    - $APP_FOLDER/.pnpm-store
    - .cache/electron
    - .cache/electron-builder

build:windows-portable:
  stage: build
  image: ciaochung/electron-dev-windows:x64-node22
  timeout: 20m
  variables:
    APP_NAME: electron-vue-app
  only:
    variables:
      - $CI_COMMIT_TAG =~ /build/
  before_script:
    - npm install -g pnpm
    - pnpm config set store-dir .pnpm-store
    - export ELECTRON_CACHE=$CI_PROJECT_DIR/.cache/electron
    - export ELECTRON_BUILDER_CACHE=$CI_PROJECT_DIR/.cache/electron-builder
  script:
    - cd $APP_FOLDER
    - pnpm install
    - pnpm build:win
    - ls -la $APP_FOLDER/dist/win-unpacked
    - du -sh $APP_FOLDER/dist/
    - cp -r $APP_FOLDER/dist/win-unpacked $CI_PROJECT_DIR/$APP_NAME
  artifacts:
    paths:
      - $CI_PROJECT_DIR/$APP_NAME
    expire_in: 1 day

 

試用心得

開發體驗的部分

electron-vite在開發使用上真的是做得非常好

照官網文件馬上就可以建立完整的template架構

然後各種平台的輸出方式都設定好

typescript也支援

而且hot repload做的

 

輸出的desktop app

檔案大小都滿大的

如果又安裝比較大型的UI framework可能會更巨大(就算有tree shaking可能還是很大)

效能上隨便就吃100-200MB的RAM

所以很多複雜又大型的應用像是vsocde

他們可能就自己刻framework避免太消耗資源以及輸出太大的檔案

 

尤其是新開視窗每開一個就多100MB左右的RAM

如果要大量開啟視窗的應用場景或是功能的話

就需要考慮是否改用flutter或是其他工具

這點我用vscode試開很多視窗也是這樣的(開一個視窗佔用1G RAM, 開3個視窗4G)

下圖是在mac上開3個視窗的RAM用量(4G)

vscode-performance

以上內容分享給也是寫web的朋友們 🔥

 

Refs