用vite插件实现一个electron-vite-react先来看下目录结构 思路实现 主进程使用esbuild进行打包
先来看下目录结构
主进程,目前electron的通讯都需要preload,所以preload单独存放了一级
渲染层,标准的vite新建项目
思路实现
使用vite启动渲染进程时,通过插件的形式创建子进程来启动主进程。
主进程使用esbuild进行打包
import esbuild from 'esbuild'
const electronBuild2Js = async () => {
// 把electron 的 入口 ts 文件进行打包操作
let context = await esbuild.context({
entryPoints: [path.join(__dirname, '../main/index.ts'), path.join(__dirname, '../main/preload/index.ts')],
bundle: true,
outdir: OUT_DIR,
loader: { '.node': 'file' }, // 配置 loader 处理 .node 文件
platform: 'node',
target: 'node16',
external: ['electron', 'sharp'],
})
await context.watch()
console.log('编译完成✅ ')
}
插件中我们使用的是configureServer这个钩子。
export const ElectronDevPlugin = (): Plugin => {
return {
name: 'electron-dev-plugin',
//配置服务的钩子
async configureServer(server) {
server.httpServer?.on('listening', async () => {
let addressInfo = server.httpServer?.address() as AddressInfo
const devUrl = `http://localhost:${addressInfo.port}`
console.log('plugins-dev : 服务的完整地址 : ', devUrl)
await electronBuild2Js()
createElectron()
const mainDir = path.join(__dirname, '../main-dist')
if (!fs.existsSync(mainDir)) {
fs.mkdirSync(mainDir)
}
})
},
}
}
createElectron方法思路:为了保证main进程被修改后会被重新加载,我们会监听打包出来的main-dist文件,我们使用的是chokidar来监听文件是否有变动,有变动则会将已经存在的子进程杀死重新启动,所以子进程的pid我们会新建一个lock文件记录一下。
const runElectron = () => {
const exit = fs.existsSync(lockFilePath)
if (exit) {
const pid = fs.readFileSync(lockFilePath, 'utf-8').toString()
if (pid) {
try {
process.kill(+pid, 'SIGTERM')
} catch (error) {
console.log('关闭electron进程失败')
}
}
}
let electronProcess = spawn(`${electron}`, [path.join(__dirname, '../main-dist/index.js')], { stdio: 'inherit' }) as ChildProcess
fs.writeFileSync(lockFilePath, `${electronProcess.pid}`)
}
creanteElectron就是去调用runElectron并且监听main进程打包出来的main-dist文件
function createElectron() {
if (!isWatch) {
const mainDir = path.join(__dirname, '../main-dist')
const debouncedCreateElectron = debounce(() => {
runElectron()
}, 200)
chokidar.watch(mainDir, { ignoreInitial: true }).on('change', (e, file) => {
debouncedCreateElectron()
})
isWatch = true
}
}
为了避免重复监听,我们会设定一个isWatch变量,如果被监听了就不会重复监听。
这样我们的插件就实现了,完整插件代码如下
// 开发环境的自定义插件
import { type Plugin } from 'vite'
import type { AddressInfo } from 'net'
// 导入子进程
import { ChildProcess, spawn } from 'child_process'
// 导入electron命令
import electron from 'electron'
// 导入 文件操作
import fs from 'fs'
import path from 'path'
import chokidar from 'chokidar'
// 引入esbuild,把 electron 的 ts 打包成 js
import esbuild from 'esbuild'
import { debounce } from 'lodash'
const OUT_DIR = path.join(__dirname, '../main-dist')
const lockFilePath = path.resolve(__dirname, '../electron.lock')
let isWatch = false
const runElectron = () => {
const exit = fs.existsSync(lockFilePath)
if (exit) {
const pid = fs.readFileSync(lockFilePath, 'utf-8').toString()
if (pid) {
try {
process.kill(+pid, 'SIGTERM')
} catch (error) {
console.log('关闭electron进程失败')
}
}
}
let electronProcess = spawn(`${electron}`, [path.join(__dirname, '../main-dist/index.js')], { stdio: 'inherit' }) as ChildProcess
fs.writeFileSync(lockFilePath, `${electronProcess.pid}`)
}
function createElectron() {
if (!isWatch) {
const mainDir = path.join(__dirname, '../main-dist')
const debouncedCreateElectron = debounce(() => {
runElectron()
}, 200)
chokidar.watch(mainDir, { ignoreInitial: true }).on('change', (e, file) => {
debouncedCreateElectron()
})
isWatch = true
}
}
// 手动定义一个方法,用于进行打包的工作
const electronBuild2Js = async () => {
// 把electron 的 入口 ts 文件进行打包操作
let context = await esbuild.context({
entryPoints: [path.join(__dirname, '../main/index.ts'), path.join(__dirname, '../main/preload/index.ts')],
bundle: true,
outdir: OUT_DIR,
loader: { '.node': 'file' }, // 配置 loader 处理 .node 文件
platform: 'node',
target: 'node16',
external: ['electron', 'sharp'],
})
await context.watch()
console.log('编译完成✅ ')
}
// 自定义的插件的逻辑
export const ElectronDevPlugin = (): Plugin => {
return {
name: 'electron-dev-plugin',
//配置服务的钩子
async configureServer(server) {
server.httpServer?.on('listening', async () => {
let addressInfo = server.httpServer?.address() as AddressInfo
const devUrl = `http://localhost:${addressInfo.port}`
console.log('plugins-dev : 服务的完整地址 : ', devUrl)
await electronBuild2Js()
createElectron()
const mainDir = path.join(__dirname, '../main-dist')
if (!fs.existsSync(mainDir)) {
fs.mkdirSync(mainDir)
}
})
},
}
}
我们在vite.config.ts文件中引入即可
plugins: [
react(),
ElectronDevPlugin(),
],
package.json文件中加入以下命令即可。
"start:react": "rm -r electron.lock && vite --config vite.config.ts",
转载自:https://juejin.cn/post/7419524503199481866