likes
comments
collection
share

用vite插件实现一个electron-vite-react先来看下目录结构 思路实现 主进程使用esbuild进行打包

作者站长头像
站长
· 阅读数 19

先来看下目录结构

主进程,目前electron的通讯都需要preload,所以preload单独存放了一级

用vite插件实现一个electron-vite-react先来看下目录结构 思路实现 主进程使用esbuild进行打包

渲染层,标准的vite新建项目

用vite插件实现一个electron-vite-react先来看下目录结构 思路实现 主进程使用esbuild进行打包

思路实现

使用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",

参考仓库 :electron-vite-react-template

转载自:https://juejin.cn/post/7419524503199481866
评论
请登录