使用electron+vue建立desktop app
關於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
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 IPC
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
portable app(在dist/mac-arm64目錄內)
- 檔案大小: 907MB
- 啟動時間: 約2-3秒
- RAM: 約180MB,跟dmg安裝的類型差不多
不過如果是要產單一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秒
輸出類型選擇
以上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)
以上內容分享給也是寫web的朋友們 🔥
Refs