前言
大前端目前发展处于高度自动化中, webpack-dev-server
这样的工具提供了向HTML注入一段监听WebSocket
的JavaScript代码来实现前端界面的热加载.
但是对于electron主进程electron-main
来说, 实现这种代码修改立即重启进程的功能是比较难实现的.
但也不是完全没有办法, 今天, 我们使用Node.js标准模块fs
来实现监听源码并自动重启electron进程.
使用fs.watch()
fs.watch()
函数监听系统文件事件, Linux下无法递归地监听一个目录, 共包括rename
和change
两种事件, 一次文件读写过程会触发多次change
事件.
fs.watch(dir, { recursive: false }, (event, filename) => {
// ...根据事件类型和文件名判断是否应该采取何种措施
});
Windows平台下强制关闭进程: taskkill
Linux下可以向进程调用kill()
函数发送信号, 或者使用pkill -ef electron
这样的命令来完成, 而Windows下只能使用taskkill
命令:
> taskkill /IM electron.exe /F
其中IM代表"Image", 映像名称.
源码auto-reload.js
/**
* 针对不同平台实现自动重载.
* 在Windows平台下通过使用taskkill /IM electron.exe /F命令强制关闭electron进程.
*/
const fs = require('fs');
const child_process = require('child_process');
const _ = require('lodash');
const rules = [
{ event: 'change', test: /^.*.js$/ },
];
/**
* 监听源码文件事件
* @param {String} dir 要监听的目录, 子目录下的文件不会被监听
* @param {Array} rules 规则数组, 每个规则是包含了"事件名"字符串和"文件名"正则表达式两个字段的对象: { event, test }
*/
function watch_source_code_file(dir, rules) {
// 递归地监视仅在Windows和OSX系统上支持。 这就意味着在其它系统上要使用替代方案。
fs.watch(dir, { recursive: true }, (event, filename) => {
rules.forEach(it => {
if (event === it.event && it.test.test(filename)) {
_handler(event, filename); // 如果源码发生了变化, 则执行_handle()函数的相关逻辑
}
});
});
// 一次"保存文件"的操作可能触发多次"change"事件, 因此使用Lodash提供的函数去抖动功能
const _handler = globalThis._handler || (globalThis._handler = _.debounce(handler, 800, { leading: true, trailing: false, }));
}
/** 编码electron主程序相关文件变化应该执行的操作 */
function handler(event, filename) {
reload_electron();
}
/** 重启electron主程序, 请调用者捕获异常 */
function reload_electron() {
try {
kill_electron();
} catch (error) {
console.error(error);
console.log('未能成功关闭electron进程, 或electron进程不存在');
}
start_electron();
}
/** 不同平台下关闭electron进程的实现 */
function kill_electron() {
if (process.platform.match(/^win.*/)) { // Implement this on Windows OS
// child_process.execSync(`taskkill /PID electron.exe /F`);
child_process.execSync(`taskkill /IM electron.exe /F`);
} else if (process.platform.match(/^linux.*/)) { // Implement this on Linux OS
globalThis.electron && globalThis.electron.kill();
}
}
/** 不同平台下启动electron进程的实现 */
function start_electron() {
if (process.platform.match(/^win.*/)) { // Implement this on Windows OS
const cmd = `start cmd /c electron "${__dirname}/main.js"`;
child_process.exec(cmd);
} else if (process.platform.match(/^linux.*/)) { // Implement this on Linux OS
const cmd = `bash -c 'electron "${__dirname}/main.js"'`; // 这里或许需要使用exec命令替换父进程, 以直接获取electron进程
globalThis.electron = child_process.exec(cmd); // Linux下可以记录PID以kill进程, 当然也可以使用"pkill -ef electron"命令
}
}
/** 主程序 */
function main() {
watch_source_code_file(__dirname, rules); // 监听项目根目录, 不含子目录, 规则在rules中定义
start_electron();
}
main();