本章将介绍如何通过vite搭建electron + vue-ts 开发环境。nodejs版本16.16.0,vite版本3.2.0,包管理工具pnpm
使用vite创建vue-ts项目
# 使用vite vue-ts模板创建项目
pnpm create vite file-manager --template vue-ts
# 进入到项目目录下,安装依赖
cd file-manager
pnpm install
修改项目结构
-
在
src
目录下创建render
目录,将src
下原有的目录及文件移入至render
目录 -
在
src
目录下创建main
和preload
目录 -
将项目根目录下的
index.html
和public
目录移入至render
目录下,修改index.html
中引入资源的路径<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vite + Vue + TS</title> </head> <body> <div id="app"></div> <script type="module" src="/main.ts"></script> </body> </html>
-
修改
vite
配置文件vite.config.ts
需要安装
@types/node
模块用于让nodejs相关api支持tsimport { defineConfig } from "vite"; import type { BuildOptions } from "vite"; import vue from "@vitejs/plugin-vue"; import { resolve } from "path"; export default defineConfig(({ mode }) => { const build: BuildOptions = { outDir: resolve(__dirname, "./dist/render") }; return { base: "./", root: resolve(__dirname, "./src/render"), build, plugins: [vue()] } });
-
修改
package.json
文件// 修改scripts属性值为如下 "scripts": { "dev:render": "vite", "build:render": "vue-tsc && vite build" }
到此,目录结构修改完毕。
执行
pnpm dev:render
运行web,在浏览器中查看web是否可以正常显示执行
pnpm build:render
打包web,查看打包出的内容路径与vite中配置的outDir
是否一致。以上两步均没问题则说明项目目录修改成功。
目录说明:
main 目录,electron主线程入口目录
preload目录,electron preload 目录(preload中的内容将会挂载到web window对象中,用于web内调用node相关API)
render目录,web目录
限制nodejs版本跟包管理器
在 package.json
中添加配置
{
// ...
"packageManager": "pnpm@7.13.4",
"engines": {
"node": "16.16.0"
},
"scripts": {
"preinstall": "npx only-allow pnpm",
// ...
}
// ...
}
在项目根目录创建npm配置文件, .npmrc
文件,添加如下内容:
engine-strict = true
代码规范设置
使用
eslint
进行代码规范。eslint
用于语法检测及代码风格约束。
-
安装
eslint
pnpm install -D eslint
-
初始化
eslint
npx eslint --init
执行eslint初始化目录后,根据项目需要在命令行交互界面选择对应选项即可。
-
修改
eslint
配置文件由于我在初始化时选择用JavaScript作为配置文件语言,所以首先要在
env
属性中加入对node的支持,否则配置文件本身会提示异常"env": { "browser": true, "es2021": true, "node": true, },
由于使用vue-ts环境作为web开发环境所以还需要增加对vue的支持
"parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" },
在配置中存在上述配置,需要将
parser
移入parserOptions
中,并重新定义parser
值为vue-eslint-parser
即可。parser: "vue-eslint-parser", parserOptions: { ecmaVersion: 'latest', sourceType: 'module', parser: "@typescript-eslint/parser" },
-
安装
vite-plugin-eslint
插件,开启vite对eslint的支持,当使用vite命令时会进行eslint验证pnpm install -D vite-plugin-eslint
在vite配置文件中引入此插件,并在plugins中声明即可。
import eslintPlugin from "vite-plugin-eslint"; // ... return { //... plugins: [ eslintPlugin() // ... ] };
初始化 git
需提前在本地安装
git
git init
引入 husky + lint-staged
husky
用于设置git钩子回调
lint-staged
用于验证暂存区文件
-
安装依赖
pnpm install -D husky lint-staged
-
配置
lint-staged
"lint-staged": { "*.{vue,ts}": "eslint" }
在执行
npx lint-staged
时会验证暂存区后缀为vue
或ts
的所有文件。 -
配置
husky
# 安装husky npx husky install # 添加git钩子 npx husky add .husky/pre-commit "npx lint-staged"
也就是说在
git commit
前执行,会先执行npx lint-staged
。
引入electron
-
安装依赖
pnpm install -D electron
-
在
src > main
目录中添加入口文件-
在该目录下初始化
typescript
。npx tsc --init
// 具体配置如下 { "compilerOptions": { "allowJs": true, "alwaysStrict": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, "jsx": "preserve", "lib": ["dom", "es2017"], "module": "commonjs", "moduleResolution": "node", "noEmit": false, "noFallthroughCasesInSwitch": true, "noUnusedLocals": false, "noUnusedParameters": true, "resolveJsonModule": true, "skipLibCheck": true, "strict": true, "target": "esnext", "outDir": "../../dist/main", }, "exclude": ["node_modules"], "include": ["**/*.ts", "**/*.tsx", "**/*.js"] }
-
创建
index.ts
文件,和main-window.ts
文件。其中index
作为项目入口,main-window
用于定义创建BrowserWindow
的相关方法。// main-window.ts import { BrowserWindow, app } from "electron"; import { resolve } from "path"; const isDev = !app.isPackaged; export function createWindow (): BrowserWindow { const minWidth = 800; const minHeight = 600; // const preloadUrl = ""; const window = new BrowserWindow({ minWidth, minHeight, frame: false, backgroundColor: "#ffffff", // webPreferences: { // preload: preloadUrl // } }); if (isDev) { window?.loadURL(`http://localhost:${process.env.PORT || 5173}`); window.webContents.openDevTools(); } else { window?.loadFile(resolve(__dirname, "../render/index.html")); window.removeMenu(); } window.on("closed", () => { window.destroy(); }); return window; }
// index.ts import { app } from "electron"; import { createWindow } from "./main-window"; async function bootstrap () { app.on("ready", () => { const window = createWindow(); }); } bootstrap();
-
-
在
package.json
文件中添加启动命令需要安装
concurrently
依赖,用于启动多个监听服务。(web服务和electron服务)pnpm install -D concurrently
{ "scripts": { "preinstall": "npx only-allow pnpm", "dev:render": "vite", "build:render": "vue-tsc && vite build", "build:electron": "tsc -p ./src/main", "dev:electron": "npm run build:electron && electron .", "dev": "concurrently \"npm run dev:render\" \"npm run dev:electron\"" } }
-
在
src > render > index.html
文件中添加meta标签
设置安全策略,避免electron
告警Insecure Content-Security-Policy
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline';">
-
设置
preload
相关内容-
在该目录下初始化
typescript
。npx tsc --init
{ "compilerOptions": { "allowJs": true, "alwaysStrict": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, "jsx": "preserve", "lib": ["dom", "es2017"], "module": "commonjs", "moduleResolution": "node", "noEmit": false, "noFallthroughCasesInSwitch": true, "noUnusedLocals": false, "noUnusedParameters": true, "resolveJsonModule": true, "skipLibCheck": true, "strict": true, "target": "esnext", "outDir": "../../dist/preload", }, "exclude": ["node_modules"], "include": ["**/*.ts", "**/*.tsx", "**/*.js"] }
-
在
src > preload
目录中创建index.ts
,types.d.ts
文件。其中:index.ts
作为preload
入口文件;types.d.ts
文件用于定义preload相关类型,并将其挂载于web端window对象上。// index.ts import { contextBridge, ipcRenderer } from "electron"; const sayHello = () => { console.log("hello"); }; const apis = { sayHello: sayHello }; export type Apis = typeof apis; contextBridge.exposeInMainWorld("ipcRenderer", ipcRenderer); contextBridge.exposeInMainWorld("Main", apis);
// types.d.ts import type { ipcRenderer } from "electron"; import type { Apis } from "./index"; declare global { interface Window { ipcRenderer: typeof ipcRenderer; Main: Apis; } }
-
在
src > main > main-window.ts
文件中引入preload并将其挂载于webPrefrences
上,以达到在web端正常访问preload
相关api的目的。// ... const window = new BrowserWindow({ // ... webPreferences: { preload: resolve(__dirname, "../preload/index.js") } }); // ...
到此electron以引入完毕,可在web端,可通过如下代码测试
if (window.Main) { window.Main.sayHello(); }
-
引入 electron-builder
处理打包事宜
-
安装
pnpm install -D electron-builder
-
配置
productName: 资料管理 nsis: oneClick: false shortcutName: 资料管理 allowToChangeInstallationDirectory: true installerIcon: ./src/render/public/logo.ico uninstallerIcon: ./src/render/public/logo.ico installerHeaderIcon: ./src/render/public/logo.ico files: - dist directories: output: dist extraResources: - data win: icon: ./src/render/public/logo.ico target: - target: nsis arch: - x64 artifactName: 资料管理.exe
-
修改
package.json
文件// 增加包描述 "description": "本地资料管理平台", "author": { "email": "1290534063@qq.com", "name": "wkj" }, // 设置脚本 (增加 build 、 dist命令,用于构建资源、打包成windows应用) "scripts": { "prepare": "husky install", "preinstall": "npx only-allow pnpm", "dev:render": "vite", "build:render": "vue-tsc && vite build", "dev:electron": "npm run build:electron && electron .", "build:electron": "npm run build:preload && tsc -p ./src/main", "build:preload": "tsc -p ./src/preload", "dev": "concurrently \"npm run dev:render\" \"npm run dev:electron\"", "build": "npm run build:render && npm run build:electron", "dist": "electron-builder" },