赞
踩
该教程依赖于这篇教程:Electron Forge + Vite + Vue3 + Ts 搭建 Electron 项目到应用打包
npm官网: rollup-plugin-copy
Vite
在打包应用时主要处理的是基于 Web 技术的项目,其工作方式和 Electron
在处理文件路径上有所不同。这种差异主要体现在以下几个方面:
Vite
通常处理的是基于 HTTP
服务器的资源路径。它假设所有资源都可以通过相对于应用的基本 URL
或端口的路径来访问。这意味着,Vite
会扫描源代码中的导入语句,查找以 HTTP URL
形式指定的资源。Electron
应用通常会访问文件系统中的资源,使用的是文件系统的绝对路径或相对于当前文件的路径。这使得 Electron
可以加载本地的文件和资源,而不依赖于 Web
服务器。Vite
打包时,它只会包括那些被静态分析到的资源文件(例如 JavaScript、CSS、图片文件等),这些文件通常是通过相对路径或模块解析方式引用的。Electron
中使用的大多都是系统路径(例如通过 __dirname 或 process.resourcesPath 生成的路径),这些路径在 Vite 的打包过程中是无法被正确识别的。在 Vite
不支持指定将某个目录打包至指定编译目录的情况下,问题逐渐变得复杂化(Forge
也没找到相关的功能)。
public
公共目录
public
是一个特殊的目录,Vite
会将这个目录里的静态资源一起输出到 web
编译目录与 Electron
编译目录,资源双份,但不失为一种解决办法。
不是很推荐这个办法,所以我直接摸了。
rollup-plugin-copy 插件
这是一个比较推荐的方案,“复制文件和文件夹”。
a. 安装 rollup-plugin-copy
npm install rollup-plugin-copy -D
b. 配置 vite.main.config.ts
文件
import copy from 'rollup-plugin-copy'
plugins: [
copy({
targets: [
{
// 要进行复制的目录或文件
src: 'static',
// 目标位置
dest: '.vite/build'
},
]
})
]
vite.main.config.ts
文件完整内容:
import type { ConfigEnv, UserConfig } from 'vite'; import { defineConfig, mergeConfig } from 'vite'; import { getBuildConfig, getBuildDefine, external, pluginHotRestart } from './vite.base.config'; // 引入 rollup-plugin-copy 插件 import copy from 'rollup-plugin-copy' // https://vitejs.dev/config export default defineConfig((env) => { const forgeEnv = env as ConfigEnv<'build'>; const { forgeConfigSelf } = forgeEnv; const define = getBuildDefine(forgeEnv); const config: UserConfig = { build: { lib: { entry: forgeConfigSelf.entry!, fileName: () => '[name].js', formats: ['cjs'], }, rollupOptions: { external, } }, plugins: [ pluginHotRestart('restart'), copy({ targets: [ { // 要进行复制的目录或文件 src: 'static', // 目标位置 dest: '.vite/build' }, ] }) ], define, resolve: { // Load the Node.js entry. mainFields: ['module', 'jsnext:main', 'jsnext'], }, }; return mergeConfig(getBuildConfig(forgeEnv), config); });
这样 static
静态资源目录就会被打包到 Electron
的编译目录内,也不会在 web
编译目录打包它。
c. 编写系统托盘,测试结果
在项目根目录创建一个 electron
目录,在这个目录里创建一个 Tray.ts
文件,用于编写系统托盘按钮逻辑,在 src/main.ts
中引用托盘内容。Electron Forge
在编译后会将 Tray.ts
合并到 main.js
中,所以我们就以 main.js
的编译位置为路径锚点,进入与其保持同级的 static
目录里获取静态资源。
在项目根目录创建一个 static
文件夹,在里面放置图片文件,例如 electron.png
:
Tray.ts
内容:
import { app, BrowserWindow, Tray, Menu, nativeImage } from 'electron'; import path from 'path'; // 窗体对象 let win: BrowserWindow; // 托盘菜单 const contextMenu = Menu.buildFromTemplate([ { label: '显示主界面', click: () => { win.show() } }, { label: '退出应用', click: () => { app.quit() } } ]) // 创建系统托盘 function createTray(w: BrowserWindow) { // 获取窗体对象 win = w; // 获取 static 下的图标文件,创建图标对象 const icon = nativeImage.createFromPath(path.join(__dirname, 'static', 'electron.png')); // 系统托盘 const concrete = new Tray(icon); concrete.setContextMenu(contextMenu); concrete.setToolTip('工具组'); // 点击托盘图标显示主窗口 concrete.on('click', () => { win.show(); }); return concrete; } export default createTray;
main.ts
内容:
main.ts
位于 src
目录下,Tray.ts
位于 src
同级目录的 electron
目录下。
import { app, BrowserWindow, Tray } from 'electron'; import path from 'path'; // 这个用于存放 ipcMain 进程通信,在这篇教程中并没有进行描述 import ipceventmount from '../electron/Ipcevent' // 引入 Tray.ts 系统托盘 import createTray from '../electron/Tray' // 窗体对象 let win: BrowserWindow; // 系统托盘 let concrete: Tray; if (require('electron-squirrel-startup')) { app.quit(); } const createWindow = () => { // 创建并获取 BrowserWindow 对象 win = new BrowserWindow({ autoHideMenuBar: true, frame: false, width: 1000, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js') } }) if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { win.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL); } else { win.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)); } } app.whenReady().then(() => { createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); ipceventmount(win); } }) if (require('electron-squirrel-startup')) app.quit(); ipceventmount(win); }).then(() => { /* 在这里创建系统托盘 */ concrete = createTray(win); }) // 全部窗口关闭时,退出应用 app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } });
app.whenReady()
得到一个当 Electron
已初始化后 fulfill
的 Promise
对象,
在第一个 .then
里创建好 BrowserWindow
对象,并将其赋值给 win
对象,
在第二个 .then
里执行 concrete = createTray(win);
创建并获取到系统托盘对象。
d. 启动测试
npm start
e. 目录结构
root L .vite # 编译目录 | L build | L main.js | L preload.js | L static | L electron.png L electron | L Tray.ts | L Ipcevent.ts L src | L main.ts | L preload.ts | L renderer.ts L static | L electron.png
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。