electron-vite-vue3-ts 快速开始

一、安装依赖

1
pnpm i electron-vite -D

二、快速构建

1
pnpm create @quick-start/electron <项目名称> --template vue-ts

三、项目结构

1.结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
├──src
│ ├──main # 主进程
│ │ ├──index.ts
│ │ └──...
│ ├──preload # 预加载脚本
│ │ ├──index.ts
│ │ └──...
│ └──renderer # 渲染器 with vue, react, etc.
│ ├──src
│ ├──index.html
│ └──...
├──electron.vite.config.ts
├──package.json
└──...

2.main/index.ts 代码解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { app, BrowserWindow, ipcMain } from 'electron'
import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'

const createWindow: Function = (): void => {
// 创建浏览器窗口
const mainWindow = new BrowserWindow({
width: 900,
height: 670,
show: false, // 窗口初始化时隐藏
autoHideMenuBar: true, // 自动隐藏菜单栏
...(process.platform === 'linux' ? { icon } : {}), // 在Linux平台上设置窗口图标
webPreferences: {
preload: join(__dirname, '../preload/index.js'), // 预加载脚本
sandbox: false // 关闭沙箱
}
})

// 当窗口准备显示时触发事件
mainWindow.on('ready-to-show', () => {
mainWindow.show() // 显示窗口
})

// 拦截新窗口请求并在外部浏览器中打开链接
// 如果要使用多页面路由,请注释这段代码
// mainWindow.webContents.setWindowOpenHandler((details) => {
// shell.openExternal(details.url) // 在默认浏览器中打开链接
// return { action: 'deny' } // 阻止Electron创建新窗口
// })

// 为 renderer 提供热模块替换(HMR)功能
// 根据是否处于开发环境加载远程URL或本地HTML文件
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']) // 加载开发环境URL
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html')) // 加载本地HTML文件
}
}

// 当Electron初始化完成并准备好创建浏览器窗口时调用此方法
// 某些API只能在此事件发生后使用
app.whenReady().then(() => {
// 为Windows平台设置应用用户模型ID
electronApp.setAppUserModelId('com.amane')

// 在开发环境下默认打开或关闭开发者工具,并在生产环境中忽略 CommandOrControl + R 快捷键
// 参见 https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window)
})

// IPC(进程间通信)测试
ipcMain.on('ping', () => console.log('pong'))

createWindow()

app.on('activate', function () {
// 在macOS系统中,当点击托盘图标且没有其他窗口打开时,常常重新创建一个窗口
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

// 当所有窗口关闭时退出应用,macOS系统除外
// 在macOS中,应用和其菜单栏会保持活动状态,直到用户按 Cmd + Q 显式退出
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})

// 在这个文件中可以包含应用主进程的其他代码
// 也可以将这些代码放到单独的文件中,再在这里引入

3.preload/index.ts 代码解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { contextBridge } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'

// 自定义渲染进程API
const api = {}

// 使用 `contextBridge` 将Electron API暴露给渲染进程
// 仅当上下文隔离启用时,否则将API添加到全局DOM窗口对象
if (process.contextIsolated) {
try {
// 如果启用了上下文隔离,则通过contextBridge暴露API
contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('api', api)
} catch (error) {
console.error(error)
}
} else {
// 如果未启用上下文隔离,直接将API添加到全局DOM窗口对象
// @ts-ignore (在d.ts中定义)
window.electron = electronAPI
// @ts-ignore (在d.ts中定义)
window.api = api
}

四、生产环境打包

1.打包指令

​ 构建好的项目打包默认不生成安装文件,需要手动指定

1
2
3
4
pnpm run build    # 打包不编译
pnpm run build:win # Windows
pnpm run build:mac # Mac
pnpm run build:linux # Linux

2.配置文件 electron-builder.yml 代码解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 打包基础配置
appId: com.amane.example # 应用程序的 ID,通常为反向域名格式
productName: electron-vite-test # 产品名称,即构建后生成的文件的基础名称
directories:
buildResources: build # 构建资源的目录,例如图标、安装包等资源
output: dist # 输出的目录,通常为 dist
files: # 打包排除文件
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
asarUnpack: # 指定不会被打包进 ASAR 文件的资源目录
- resources/**
# extraResources: # 指定要包含在构建包中的其他资源,例如数据库、配置文件等
# - from: "extraResources/" # 来源目录
# to: "extraResources" # 打包后的目标目录

# Windows 平台的特定配置
win:
target: # 目标打包格式,通常是 nsis(Nullsoft Scriptable Install System)
- nsis
icon: 'build/icon.ico' # 应用图标
# legalTrademarks: "My Trademark" # 法律商标
# verifyUpdateCodeSignature: false # 禁用更新代码签名的验证
nsis: # NSIS 安装程序配置
oneClick: false # 禁用一键安装
perMachine: true # 允许为所有用户安装
allowToChangeInstallationDirectory: true # 允许用户更改安装目录
createDesktopShortcut: always # 始终创建桌面快捷方式
shortcutName: "${productName}" # 快捷方式的名称
# signingHashAlgorithms: # Windows 代码签名的证书属性
# - sha256
# certificateFile: 'path/to/your-certificate.pfx' # 代码签名证书文件路径
# certificatePassword: 'your-password' # 代码签名证书密码

# macOS 平台的特定配置
mac:
target: # 目标打包格式,通常是 dmg
- dmg
icon: 'build/icon.icns' # 应用图标
category: "public.app-category.utilities" # 应用类别
hardenedRuntime: true # 启用硬化运行时
entitlements: "build/entitlements.mac.plist" # 权限配置文件
entitlementsInherit: "build/entitlements.mac.inherit.plist" # 继承权限配置文件
gatekeeperAssess: false # 禁用门卫评估
dmg:
# DMG 安装包配置
background: "build/background.png" # DMG 安装包背景图片
icon: "build/icon.icns" # DMG 安装包图标
iconSize: 100 # 图标大小
artifactName: "${productName}-v${version}.${ext}" # 生成的 DMG 文件名称格式

linux:
# Linux 平台的特定配置
target:
- AppImage # 目标打包格式,通常是 AppImage
- snap # 音关闭相关格式
- deb # 目标打包格式,通常是 deb
maintainer: ${author} # 维护者信息
vendor: "Your Company" # 供应商信息
synopsis: "一个简短的应用描述" # 应用简述
description: "一个详细的应用描述" # 应用详细描述
category: "Utility" # 应用类别
appImage: # AppImage 安装包的相关配置
artifactName: ${name}-${version}.${ext} # 生成的 AppImage 文件的名称格式

# 其它配置
publish: # 发布配置,用于自动更新等
provider: generic # 使用通用发布方式
url: "https://example.com/updates/" # 自动更新的 URL
npmRebuild: false # 是否在打包前重新构建本地 Node.js 模块
# releaseNotes: "Release notes for version ${version}" # Electron Builder 的 'releaseNotes',用于在更新期间提供变更日志
# npmArgs: ["--runtime=electron", "--target=2.0.4", "--disturl=https://atom.io/download/atom-shell"] # 启用 Yarn 处理依赖关系
# sourceMaps: true # 启用 source-map,用于更好的调试
# prune: true # 在打包过程中是否删除所有 devDependencies

五、备注

该项目没有装配大多数常见依赖(如 router、pinia 等),需手动添加。