前言
大前端目前發展處於高度自動化中, 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();
