electron ,实时调试运行项目
效果
主进程.mjs 和 预加载脚本.mjs 里修改代码后, 会重新启动运行
网页页面直接热加载更新
文件夹结构如下
---代码
|---- main ----- 主进程.mjs
| |----vite.config.mjs (打包主进程)
|----- preload ----- 预加载脚本.mjs
| |----vite.config.mjs (打包预加载)
|---- renderer ---- index.html
|---- index2.html
|----vite.config.mjs (开启3000端口 和 HMR 热加载,打包所有 UI 界面网页)
🍎🍎记录一个奇怪的问题::::: 预加载脚本是ECMAScript .mjs文件,且用loadURL 加载窗口时,预加载脚本里不能使用 lodash-es !!! 否则出现预加载脚本滞后执行,无法打开窗口
前提
修改主进程的窗口 BrowserWindow
const 新窗口 = new BrowserWindow({ ... })
if (app.isPackaged) 新窗口.loadFile("path/to/文件路径/index.html" ) //加载网页
else 新窗口.loadURL('http://localhost:3000/App主窗口/index.html')
// 3000 端口 是渲染进程 watch.mjs 里定义的 ,路径是网页的 vite.config.mjs 决定的
核心工作
项目package.json > scripts 里添加 "dev": "node ./watch.mjs"
启动脚本 npm run dev
ps: 注意 skipWrite:true 如果不需要就关闭
//================== 文件名 watch.mjs =========================
//启动脚本 npm run dev
import child_process from 'child_process'
import { createServer, build as vite_build } from 'vite'
// electron 绝对路径,Windows 为 electron.exe
import electronPath from 'electron'
async function 开始调试(){
// ---- 渲染进程部分 ----
// 这里决定主进程里窗口 BrowserWindow --> 窗口.loadURL() 加载网页时的端口 3000
const server = await createServer({
configFile: '代码/renderer/vite.config.mjs' , // 这里决定 BrowserWindow --> 窗口.loadURL() 的加载路径
build: { watch: { skipWrite:true }, },
server: { host: "0.0.0.0" ,port:3000, hmr: true }, // 为开发服务启用热更新,默认是不启用热更新的
})
await server.listen()
console.log("1 🌷🌷 渲染进程服务 完成")
let 此脚本启动完成 = false
let 主进程 = null
// ----- 预加载脚本
// 现存的 bug ::: 用loadURL 加载窗口时, 预加载脚本里不能使用 lodash-es 否则出现 预加载脚本滞后执行,无法打开窗口
await vite_build({
configFile: '代码/preload/vite.config.mjs', // 只监控,不使用,skipWrite:true
build: { watch: { skipWrite:true }, }, // 通过 watch 选项监听主进程文件改动,时时编译
plugins: [{
name: 'electron-preload', // 这是个自定义插件
closeBundle() { // 第一次编译、重新编译后都会触发
if(!此脚本启动完成) return
if(主进程) 主进程.kill() // 相当于官方的 electron . 启动方式
主进程 = child_process.spawn( electronPath, ['.'], {stdio:'inherit'}, )
console.log("🍍🍍 预加载脚本变动, 重启")
},
}],
})
console.log("2 ☘️☘️ 预加载脚本 完成")
// ---- 主进程部分 ----
await vite_build({
configFile: '代码/main/vite.config.mjs', // 只监控,不使用,skipWrite:true
build: { watch: { skipWrite:true }, }, // 通过 watch 选项监听主进程文件改动,时时编译
plugins: [{
name: 'electron-main-starter', // 自定义插件
closeBundle() { // 第一次编译、重新编译后都会触发
if(主进程) 主进程.kill() // 相当于官方的 electron . 启动方式
主进程 = child_process.spawn(electronPath, ['.'], {stdio:'inherit'}, )
此脚本启动完成 = true
console.log("🍍🍍 主进程变动, 重启")
},
}],
})
console.log("3 🍊🍊 主进程部分 完成")
}
开始调试()
渲染进程,也就网页的打包配置如下
示范,参考 vite.config.mjs
import { builtinModules } from 'module'
import {defineConfig} from "vite"
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
// import vueExtendOptions from "vite-plugin-vue-setup-extend"
import { dirname } from 'path'
import { fileURLToPath } from 'url'
const __dirname = dirname(fileURLToPath(import.meta.url))
export default defineConfig({
plugins: [
vue( ), //处理 vue文件
// vueExtendOptions(), //选项 API 为组件命名
// nodeResolve(), //使用 "node 解析算法" 来定位模块,用于使用 node_modules 中的第三方模块。
// commonjs(), //用于将CommonJS模块转换为ES6,这样它们就可以包含在Rollup包中
// terser(), //代码压缩
// viteSingleFile() // 代码合成单文件
// copy({ targets: [{ src: path.join(窗口目录,'./窗口.html'), dest: 窗口文件输出目录 }], }),
],
//server: { host: "0.0.0.0" ,port:3000, hmr: true, // 为开发服务启用热更新,默认是不启用热更新的 },
root: __dirname, // 指向渲染进程目录
base: './', // index.html 中静态资源加载位置;如 src="./index.js"
build: {
outDir: './dist',
// outDir: '../../dist/renderer',
assetsDir: '', // 这个要格外小心,使用默认的 assets 会导致在 Electron 打包后基于 file:// 加载文件失败
loader:{ ".exe":"file",".css":"file" ,".png":"file",".svg":"file"},
bundle:true,
emptyOutDir:true,
rollupOptions: {
//input这里生产 html 可运行网页
input:{ // 覆盖默认的 .html 入口 多文件
"App主窗口": resolve(__dirname,'App主窗口/index.html'),
"App文件移动窗口": resolve(__dirname,'App文件移动窗口/index.html'),
"App终端窗口": resolve(__dirname,'./App终端窗口/index.html'),
},
output: {
format: 'esm', //必须 Electron 28.0 支持esm
manualChunks: undefined, //将所有的未使用资源进行移除
chunkFileNames: '[name]-[hash].mjs',
entryFileNames: '[name]-[hash].mjs',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]' ,
},
external: [ // 告诉 Rollup 不要打包内建 API
...[ "node-pty"], // 'vue' 不想打包进库的依赖 比如 "path" "os",
...builtinModules,
],
treeshake:true, //是一种通过消除最终文件中未使用的代码来优化体积的方法。
},
},
optimizeDeps: {
exclude: ['electron'], // 告诉 Vite 排除预构建 electron,不然会出现 __diranme is not defined
},
resolve:{
alias:[
// {find:'@',replacement: path.resolve(项目目录)} , // import 里碰到 @替换
{find:'vue',replacement:'vue/dist/vue.esm-bundler.js'} // import 'vue' 时找到的文件 带有运行时vue.runtime.esm-browser.js
],
},
define: {
__VUE_OPTIONS_API__: false // 关闭 Vue2 中的 options选项API
},
// 其他配置略...
})