Skip to content

Commit 2a42a4f

Browse files
✨ add electron-builder
1 parent 7792a93 commit 2a42a4f

File tree

8 files changed

+136
-14
lines changed

8 files changed

+136
-14
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ playwright-report/
3535
/yarn.lock
3636
/pnpm-lock.yaml
3737
/package-lock.json
38+
39+
/release

.npmrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
save-exact=true
22
engine-strict=true
3+
registry=http://registry.npmmirror.com
4+
electron_mirror=https://npmmirror.com/mirrors/electron/
5+
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/

electron-builder.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Configuration } from 'electron-builder'
2+
3+
export default <Configuration>{
4+
// 应用唯一标识
5+
appId: `cn.com.xuxiaowei.${process.env.npm_package_name}`,
6+
// 版权信息
7+
copyright: 'Copyright © 徐晓伟 https://xuxiaowei.com.cn',
8+
// 打包产物名称
9+
artifactName: '${productName}-${version}-${platform}-${arch}.${ext}',
10+
// 使用 asar 打包
11+
asar: true,
12+
// asar 打包后解压的文件(运行前会自动解压)
13+
asarUnpack: [],
14+
// 打包 删除 package.json 的 scripts
15+
removePackageScripts: true,
16+
// 打包 删除 package.json 的 keywords
17+
removePackageKeywords: true,
18+
// 是否从应用程序版本号推断更新通道。例如,如果版本为 0.12.1-alpha.1,则 channel 将被设置为 alpha。否则为 latest。
19+
detectUpdateChannel: true,
20+
// 是否在发布时自动生成更新文件。如果设置为 true,则会在发布时自动生成更新文件,否则需要手动生成。
21+
generateUpdatesFilesForAllChannels: true,
22+
// 打包的文件
23+
files: [
24+
// Vite 打包后的文件
25+
'dist/**/*',
26+
// 程序入口文件
27+
'main.js',
28+
// 预加载文件
29+
'preload.js',
30+
],
31+
// 生成资源的目录
32+
directories: {
33+
output: 'release/${version}',
34+
},
35+
}

main.js

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import { app, BrowserWindow } from 'electron'
1+
// Modules to control application life and create native browser window
2+
3+
import { app, net, protocol, BrowserWindow } from 'electron'
24
import path from 'path'
3-
import { fileURLToPath } from 'node:url'
5+
import { fileURLToPath } from 'url'
46
import log from 'electron-log'
57
import Store from 'electron-store'
8+
import fs from 'fs/promises'
69

710
const store = new Store()
811

@@ -23,8 +26,14 @@ log.scope.labelPadding = 8
2326

2427
log.info('Hello from Electron 👋')
2528

26-
let devTools = store.get('devTools')
27-
if (!(devTools instanceof Boolean)) {
29+
// 创建一个新的日志记录器
30+
const loader = log.create({ logId: 'loader' })
31+
loader.transports.file.fileName = 'loader.log'
32+
loader.scope.defaultLabel = 'loader'
33+
loader.scope.labelPadding = 8
34+
35+
const devTools = store.get('devTools')
36+
if (typeof devTools !== 'boolean') {
2837
store.set('devTools', process.env.NODE_ENV === 'development')
2938
}
3039

@@ -38,7 +47,35 @@ if (!(devTools instanceof Boolean)) {
3847
// Linux 安装 *.snap:~/snap/项目名/x1/.config/项目名/config.json
3948
log.info('electron-store path', store.path)
4049

50+
// 协议名称,自定义
51+
const scheme = 'vvt'
52+
53+
// 新增协议注册函数
54+
const registerProtocol = () => {
55+
protocol.handle(scheme, async (request) => {
56+
const url = request.url
57+
const parsedUrl = url.substring(scheme.length + 3).replace(/^(\.\.(\/|\\|$))+/, '')
58+
const requestedPath = path.join(__dirname, parsedUrl)
59+
const normalizedPath = path.normalize(requestedPath)
60+
61+
try {
62+
await fs.access(normalizedPath, fs.constants.R_OK)
63+
loader.info(
64+
`url: ${url}, parsedUrl: ${parsedUrl}, requestedPath: ${requestedPath}, normalizedPath: ${normalizedPath}`,
65+
)
66+
return net.fetch(`file://${normalizedPath}`)
67+
} catch {
68+
const fallbackPath = path.join(__dirname, 'dist', 'index.html')
69+
loader.warn(
70+
`url: ${url}, parsedUrl: ${parsedUrl}, requestedPath: ${requestedPath}, fallbackPath: ${fallbackPath}`,
71+
)
72+
return net.fetch(`file://${fallbackPath}`)
73+
}
74+
})
75+
}
76+
4177
const createWindow = () => {
78+
// Create the browser window.
4279
const mainWindow = new BrowserWindow({
4380
width: 800,
4481
height: 600,
@@ -48,23 +85,49 @@ const createWindow = () => {
4885
},
4986
})
5087

51-
mainWindow.loadURL(process.env.VITE_SERVER_URL)
88+
if (process.env.VITE_SERVER_URL) {
89+
mainWindow.loadURL(process.env.VITE_SERVER_URL).catch((err) => {
90+
log.error('mainWindow.loadURL', process.env.VITE_SERVER_URL, err)
91+
})
5292

53-
mainWindow.webContents.openDevTools()
93+
// Open the DevTools.
94+
mainWindow.webContents.openDevTools()
95+
} else {
96+
// and load the index.html of the app.
97+
mainWindow.loadURL(`${scheme}://dist/index.html`).catch((err) => {
98+
log.error('mainWindow.loadURL', err)
99+
})
100+
}
54101
}
55102

103+
// This method will be called when Electron has finished
104+
// initialization and is ready to create browser windows.
105+
// Some APIs can only be used after this event occurs.
56106
app.whenReady().then(() => {
107+
// 只在生产环境注册协议
108+
if (!process.env.VITE_SERVER_URL) {
109+
registerProtocol()
110+
}
111+
57112
createWindow()
58113

59-
app.on('activate', () => {
114+
app.on('activate', function () {
115+
// On macOS it's common to re-create a window in the app when the
116+
// dock icon is clicked and there are no other windows open.
60117
if (BrowserWindow.getAllWindows().length === 0) {
61118
createWindow()
62119
}
63120
})
64121
})
65122

123+
// Quit when all windows are closed, except on macOS. There, it's common
124+
// for applications and their menu bar to stay active until the user quits
125+
// explicitly with Cmd + Q.
66126
app.on('window-all-closed', () => {
67127
if (process.platform !== 'darwin') {
68128
app.quit()
69129
}
70130
})
131+
132+
// In this file you can include the rest of your app's specific main process
133+
// code. You can also put them in separate files and require them here.

package.json

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"pre:pnpm": "pnpm install --registry https://registry.npmmirror.com || pnpm install --registry https://registry.npmjs.org",
1717
"dev": "vite",
1818
"build-only": "vite build",
19-
"build": "run-p type-check \"build-only {@}\" --",
19+
"build": "run-p type-check \"build-only {@}\" -- && electron-builder",
2020
"preview": "vite preview",
2121
"test:unit": "vitest",
2222
"test:e2e": "playwright test",
@@ -32,6 +32,7 @@
3232
},
3333
"keywords": [
3434
"electron",
35+
"electron-builder",
3536
"electron-log",
3637
"electron-store",
3738
"pinia",
@@ -44,10 +45,7 @@
4445
],
4546
"dependencies": {
4647
"electron-log": "5.3.3",
47-
"electron-store": "10.0.1",
48-
"pinia": "3.0.1",
49-
"vue": "3.5.13",
50-
"vue-router": "4.5.0"
48+
"electron-store": "10.0.1"
5149
},
5250
"devDependencies": {
5351
"@playwright/test": "1.51.1",
@@ -62,6 +60,7 @@
6260
"@vue/test-utils": "2.4.6",
6361
"@vue/tsconfig": "0.7.0",
6462
"electron": "35.1.2",
63+
"electron-builder": "26.0.12",
6564
"eslint": "9.23.0",
6665
"eslint-plugin-oxlint": "0.16.4",
6766
"eslint-plugin-playwright": "2.2.0",
@@ -70,11 +69,14 @@
7069
"jsdom": "26.0.0",
7170
"npm-run-all2": "7.0.2",
7271
"oxlint": "0.16.4",
72+
"pinia": "3.0.1",
7373
"prettier": "3.5.3",
7474
"typescript": "5.8.2",
7575
"vite": "6.2.4",
7676
"vite-plugin-vue-devtools": "7.7.2",
7777
"vitest": "3.1.1",
78+
"vue": "3.5.13",
79+
"vue-router": "4.5.0",
7880
"vue-tsc": "2.2.8"
7981
},
8082
"engines": {

preload.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
/**
2+
* The preload script runs before `index.html` is loaded
3+
* in the renderer. It has access to web APIs as well as
4+
* Electron's renderer process modules and some polyfilled
5+
* Node.js functions.
6+
*
7+
* https://www.electronjs.org/docs/latest/tutorial/sandbox
8+
*/
9+
110
console.log('preload.js')
211

312
window.addEventListener('DOMContentLoaded', () => {

renderer.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1+
/**
2+
* This file is loaded via the <script> tag in the index.html file and will
3+
* be executed in the renderer process for that window. No Node.js APIs are
4+
* available in this process because `nodeIntegration` is turned off and
5+
* `contextIsolation` is turned on. Use the contextBridge API in `preload.js`
6+
* to expose Node.js functionality from the main process.
7+
*/
8+
19
console.log('renderer.js')

src/router/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { createRouter, createWebHistory } from 'vue-router'
1+
import { createRouter, createWebHashHistory } from 'vue-router'
22
import HomeView from '../views/HomeView.vue'
33

44
const router = createRouter({
5-
history: createWebHistory(import.meta.env.BASE_URL),
5+
history: createWebHashHistory(import.meta.env.BASE_URL),
66
routes: [
77
{
88
path: '/',

0 commit comments

Comments
 (0)