新人前端,有不足之处请多多指教
本文是Electron实战系列的第一篇,主要介绍如何一步一步搭建自己的Electron开发环境,以及如何创建一个简单的Electron应用。
技术:electron、esbuild、Livereload、chokidar
环境:Node.js v20.18.1、electron v34.2.0、Windows 11
最基础的electron应用只需要一个主进程main.js和一个渲染进程index.html即可,但是为了更好的开发体验,我们还需要一些工具来辅助开发,比如热刷新、打包等。
在本文中,我们要完成以下几个目标:
- 主进程打包及监听重启
- 渲染进程打包及热刷新
- preload打包及热刷新
主进程打包及监听重启
在开发前,我们需要意识到Electron应用应当由另一个进程来进行控制,通过这个进程可以实现对主进程js的监听,进而实现监听重启。
// 打包主进程与创建index.html文件
const buildElectron = async () => {
await esbuild.build({
entryPoints: ['./master/index.ts'],
outfile: './dist/master.js',
platform: 'node',
bundle: true,
external: ['electron'],
format: 'esm',
});
if (!await fsExists('./dist/renderer')) {
await fs.writeFile('./dist/index.html', `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Electron App</title>
</head>
<body>
<h1>Hello, Electron!</h1>
<script src="./render.js"></script>
</body>
</html>
`);
}
};
在esbuild打包的参数中需要注意的是,external一定要加上electron,因为我们不需要将electron打包进去,而是在运行时由electron来加载;在最新的electron版本中,直接支持主进程与渲染进程的esm模式,所以format直接设置为esm即可。
// 监听主进程文件变化并重启
chokidar.watch('./master').on('change', async () => {
await buildElectron();
electronCP.removeAllListeners();
electronCP.once('exit', startElectron);
electronCP.kill();
});
// 启动Electron
const startElectron = () => {
electronCP = cp.spawn(electron, [path.join(__dirname, 'dist/master.js')]);
electronCP.stdout.on('data', (chunk) => {
process.stdout.write(`[master] ${chunk}`);
});
electronCP.stderr.on('data', (chunk) => {
process.stderr.write(`[master ERR] ${chunk}`);
});
electronCP.once('close', process.exit);
};
startElectron();
使用chokidar监听主进程文件的变化,这里的监听规则可以根据自己的需求来设置。注意当主进程文件发生变化时,在杀死electron进程前,需要先移除所有的监听器,否则会导致前一个监听器被触发,导致build进程也被杀死。
渲染进程打包及热刷新
渲染进程热刷新是通过Livereload来实现的。livereload工作原理是在nodejs中启动一个服务器,并且通过与浏览器预先注入的livereload脚本进行连接,进而实现浏览器的刷新。
// 创建livereload服务器
import livereload from 'livereload';
const liveServer = livereload.createServer({port: 35729});
// 打包主进程与创建index.html文件
const buildElectron = async () => {
···略
if (!await fsExists('./dist/renderer')) {
await fs.writeFile('./dist/index.html', `
<!DOCTYPE html>
<html lang="en">
<body>
<h1>Hello, Electron!</h1>
+ <script>
+ const script = document.createElement('script');
+ script.src = 'http://' + (location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1';
+ document.body.appendChild(script);
+ </script>
<script src="./render.js"></script>
</body>
</html>
`);
}
};
// 打包渲染进程
const buildRender = async () => {
await esbuild.build({
entryPoints: ['./render/index.ts'],
outfile: './dist/render.js',
platform: 'browser',
bundle: true,
});
};
// 监听渲染进程文件变化并刷新
chokidar.watch('./render').on('change', async () => {
await buildRender();
liveServer.refresh('/');
});
preload打包及热刷新
preload较为简单,需要注意的是preload要打包为一个文件,并且模块为commonjs。
// 打包preload
const buildPreload = async () => {
await esbuild.build({
entryPoints: ['./preload/index.ts'],
outfile: './dist/preload.js',
platform: 'node',
bundle: true,
external: ['electron'],
format: 'cjs',
});
};
// 监听并热刷新代码略
总结
在实际应用中,根据自身的需求可以修改或增加一些功能,比如打包时的压缩、代码检查等。同样的,构建工具可以使用Vite、Rspack等,这里使用esbuild是因为它的速度快,且用法简单,依赖较少。
注意:
- 本地nodejs版本应尽量与electron node版本一致,防止出现实现不一致。
- 如果需要实现源码debug,可以配置esbuild sourcemap来实现。