Electron + Vue 项目从零创建,不使用 vue-electron-template
Electron + Vue 项目创建
1. vite项目框架搭建
按照一般的开发流程,用命令行创建一个vite项目:
# use npm or yarn or pnpm
npm(yarn | pnpm) create vite
根据自己的需要,选择相应的选项。创建完成后,进入项目,安装依赖并运行,一个基础的vite项目就创建好了。
ex:默认创建时,可能需要的额外操作
-
TS支持
由于vite默认使用esbuild处理TS,天然支持它,因此只需要添加TS相关依赖,并编写tsconfig.json以应用TS检查即可。
# use npm or yarn or pnpm npm install -D typescript vue-tsc
// tsconfig.json { "compilerOptions": { "target": "esnext", "module": "esnext", "strict": true, "jsx": "preserve", "moduleResolution": "node", "isolatedModules": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, "useDefineForClassFields": true, "sourceMap": true, "baseUrl": ".", "types": [ "webpack-env" ], "paths": { "@/*": [ "src/*" ] }, "lib": [ "esnext", "dom", "dom.iterable", "scripthost" ] }, "include": [ "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts", "tests/**/*.tsx" ], "exclude": [ "node_modules" ] }
// package.json { ... "scripts": { "dev": "vite --host", "build": "vue-tsc && vite build", } }
-
vue-router和vuex/pinia
添加依赖后正常在main.ts中引入即可。
# use npm or yarn or pnpm npm install vue-router vuex(or pinia)
// src/main.ts import { createApp } from "vue"; import router from "./router"; import store from "./store"; import "./style.css"; import App from "./App.vue"; createApp(App).use(router).use(store).mount("#app"); // or import { createApp } from 'vue' import { createPinia } from 'pinia' import router from './router' import App from './App.vue' import "./style.css"; const app = createApp(App) app.use(createPinia()) app.use(router) app.mount('#app')
-
eslint & prettier
正常安装依赖,编写配置文件即可,这里我没有编写.prettierrc.js,用的默认配置。
# use npm or yarn or pnpm npm install -D eslint prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue @typescript-eslint/parser vue-eslint-parser
// .eslintrc.js module.exports = { root: true, env: { node: true, // The Follow config only works with eslint-plugin-vue v8.0.0+ "vue/setup-compiler-macros": true, }, extends: [ "plugin:vue/vue3-essential", "eslint:recommended", "@vue/typescript/recommended", "plugin:prettier/recommended", ], plugins: ["vue"], parser: "vue-eslint-parser", parserOptions: { parser: "@typescript-eslint/parser", ecmaVersion: 2020, sourceType: "module", }, rules: { "no-console": import.meta.env.NODE_ENV === "production" ? "warn" : "off", "no-debugger": import.meta.env.NODE_ENV === "production" ? "warn" : "off", "prettier/prettier": ["error", { endOfLine: "auto" }], "no-unreachable": "warn", "vue/no-unused-vars": "warn", "@typescript-eslint/no-var-requires": "off", }, globals: {}, };
-
css预处理器
由于vite内置了关于css预处理的支持,因此只需安装相应的预处理器依赖即可,以less为例:
# use npm or yarn or pnpm npm install -D less
2. electron集成
1. 集成
注:由于package.json中的dependencies是在node生产环境运行时需要的,而electron是完全游离在node之外的,因此不需要生产环境的依赖,安装在devDependecies下即可。
安装electron用默认源可能会比较耗时,建议用nrm换源到taobao:
# use npm or yarn or pnpm
npm install -g nrm
nrm use taobao
然后安装electron:
# use npm or yarn or pnpm
npm install -D electron
若不切换taobao源基本会在此处报错ETIMEOUT,解决方法如下:
# use npm or yarn or pnpm
npm config set ELECTRON_MIRROR https://npmmirror.com/mirrors/electron/
# 或项目根目录新建.npmrc文件,并在其中添加
electron_mirror=https://npmmirror.com/mirrors/electron/
此时已经可以编写electron程序了,让我们写一个main.js创建electron主进程:
// electron/main.js
import { app, BrowserWindow } from "electron";
const path = require('path');
const createWindow = () => {
const win = new BrowserWindow({
webPreferences: {
contextIsolation: false, // 是否开启隔离上下文
nodeIntegration: true, // 渲染进程使用Node API
preload: path.join(__dirname, "./preload.ts"), // 需要引用js文件
},
});
// 如果打包了,渲染index.html
if (app.isPackaged) {
win.loadFile(path.join(__dirname, "../dist/index.html"));
} else {
win.loadURL("http://127.0.0.1:5173");
}
};
app.whenReady().then(() => {
createWindow(); // 创建窗口
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// 关闭窗口
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
然后在package.json中指定electron程序的主进程入口,并添加electron启动脚本:
// package.json
{
"name": "electron-vue-demo",
"private": true,
"version": "0.0.0",
"type": "commonjs", // 注意,这里必须被指定为commonjs,否则打包时无法解析node的commonjs模块
"author": "cyanAir",
"main": "./electron/main.js", // 主进程入口
"scripts": {
"dev": "vite --host",
"build": "vue-tsc && vite build",
"dev:electron": "./electron/main.js"
},
...
}
此时先运行npm run dev
然后运行npm run dev:electron
就可以看见已经启动了electron项目,如下:
2. 启动流程优化
由于每次启动都需要先启动vue再启动electron有点麻烦,而且由于vue项目默认ts编译不产生产物的问题,无法通过使用ts编写electron主进程相关的代码。此时需要引入vite-plugin-electron
插件:
# use npm or yarn or pnpm
npm install -D vite-plugin-electron
之后在vite.config.ts中引入:
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import electron from "vite-plugin-electron";
import * as path from "path";
export default defineConfig({
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
"#": path.resolve(__dirname, "electron"),
}
},
plugins: [
vue(),
electron({
entry: ["electron/main.ts", "electron/preload.ts"], // electron主进程调用入口文件、preload文件
vite: {
build: {
rollupOptions: {
// c/c++链接库
external: [],
},
},
},
}),
],
build: {
emptyOutDir: true, // 默认情况下,若 outDir 在 root 目录下,则 Vite 会在构建时清空该目录
},
});
而后将electron/mian.js
改为main.ts,之后main.ts会在electron运行前编译,编译产物会出现在dist-electron/
目录下,因此同时需要更改package.json中的main参数,如下:
// package.json
{
...
"main": "./dist-electron/main.js", // 主进程入口
...
}
此后只需要运行npm run dev
,就会自动运行electron。
⭐注意:上方使用的插件版本为v0.11.2,由于这个commit,若希望使用v0.15.x及之后的版本,需要修改使用方式为如下形式:
plugins: [ vue(), electron([ { entry: ["electron/preload.ts"] }, { entry: ["electron/main.ts"], // electron主进程调用入口文件 vite: { build: { rollupOptions: { // c/c++链接库 external: [], }, }, }, }, ]), ],
3. 开发环境web devtools引入
web开发过程中,通常需要通过devtools进行调试,因此在electron应用中很有必要引入devtools,先安装electron-devtools-installer
:
# use npm or yarn or pnpm
# 取决于生产环境是否需要使用,安装在dep还是devDep下需要自己决定
npm install -D electron-devtools-installer
然后在electron/main.ts中
引入:
// electron/main.ts
import installExtension, { VUEJS3_DEVTOOLS } from "electron-devtools-installer";
const isDevelopment = !import.meta.env.PROD; // 环境
...
app.whenReady().then(() => {
createWindow(); // 创建窗口
if (isDevelopment) {
// Install Vue Devtools
try {
await installExtension(VUEJS3_DEVTOOLS);
} catch (e: any) {
console.error("Vue Devtools failed to install:", e.toString());
}
}
win.webContents.openDevTools({ mode: "right", activate: true }); // 默认在右侧打开开发工具
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
此后可以通过在electron应用中ctrl + shift + i
打开/关闭开发工具。
4. 应用打包
electron应用打包官方推荐的是elelctron-forge
,我当时没有用的这个包,用的electron-builder
,因此下面我只会讲electron-builder
的打包。
首先需要安装electron-builder
# use npm or yarn or pnpm
npm install -D electron-builder
然后在package.json中添加build参数,具体参数见electron-builder官网:
// package.json
{
...
"build": {
"appId": "com.my-website.my-app", // 应用id,两个如果相同的话,安装会覆盖
"productName": "MyApp", // 应用名,打包后的应用名称
"copyright": "Copyright © 2022 ${author}", // 著作权
"asar": true, // 是否使用asar归档文件,详情可以看https://www.electronjs.org/zh/docs/latest/tutorial/asar-archives
"npmRebuild": false, // 是否每次打包时都用npm rebuild重新构建node模块生成对应的动态链接库
"extraResources": [ // 纯静态资源(不经历build过程,单纯拷贝,类似webpack中的copy-webpack-plugin)
{
"from": "config.conf",
"to": "../"
},
],
"directories": {
"buildResources": "assets", // 静态资源路径
"output": "release/${version}" // 输出地址
},
"files": [ // 需要进行打包的文件/目录
"dist/**/*",
"dist-electron/**/*"
],
"win": { // windows打包相关配置
"target": [ // 打包产物
{
"target": "nsis", // 使用的安装包程序
"arch": [ // 架构
"x64"
]
}
],
"artifactName": "${productName}_${version}.${ext}" // 安装包名称
},
"nsis": { // nsis安装包程序配置
"oneClick": false, // 是否一键安装
"language": "2052", // 默认语言,2052-简体中文
"perMachine": false, // 是否默认为PC上的每一个用户安装
"allowToChangeInstallationDirectory": true, // 是否允许自定义安装目录
"deleteAppDataOnUninstall": false // 卸载时是否删除AppData目录下的文件
}
},
}
然后再添加electron-builder打包的脚本:
{
...
"script": {
...
"electron:build": "vue-tsc && vite build && electron-builder",
},
...
}
此时若直接运行,会报下面的错:
这是由于vue-tsc进行ts检查时发现有模块不能生成js产物导致的,在tsconfig.json中添加:
// tsconfig.json
{
"compilerOptions": {
...
"noEmit": true,
},
...
}
在这之后就可以进行打包了,打包后的产物如图:
其中win-unpacked/
为打包后的可执行程序,MyApp_0.0.0.exe
为安装包。
此时打开win-unpacked/MyApp.exe(或安装后打开应用程序),应该可以正常看到应用画面。
5. 应用日志
在打包后,我们的浏览器控制台一般情况下是无法打开的,此时如果发生了错误,我们就需要应用日志帮助我们定位问题所在。
首先安装electron-log
:
npm install electron-log
然后在需要的地方引入(以应用入口为例,一般应用入口会有一个全局错误处理的方法):
const log = require("electron-log");
...
// 异常捕获,避免异常闪退
process.on("uncaughtException", (e) => {
log.error(e);
});
其中log文件默认路径为:
%USERPROFILE%\AppData\%PROJECT_NAME%\logs\main.log // Windows
~/.config/{app name}/logs/main.log // Linux
~/Library/Logs/{app name}/main.log // MacOS
如果希望修改可以通过log.transports.file.resolvePath = () => PATH
和log.transports.fileName
来修改,其中reslovePath
的定义如下:
resolvePathFn: (variables: PathVariables, message?: LogMessage) => string;
electron-log
的具体用法详见其npm包。
6. 路径引用
electron中文件路径与普通的vue项目略有不同,下面进行说明。
-
vue项目中文件之间的相互引用不需要做任何修改,因为vue部分在vite打包之后会被作为一个整体放入asar归档文件中,因此可以正常引用。
-
electron及node后端部分若需要进行文件读取等操作,有三种定义的路径(MacOS、Linux类似):
__dirname => %USERPROFILE%\AppData\Local\Programs\MyApp\resources\app.asar\%FILE_DIRNAME% app.getAppPath() => %USERPROFILE%\AppData\Local\Programs\MyApp\resources\app.asar process.cwd() => exe程序文件所在的目录
7. 非node原生模块的构建
未完待续