Electron开发记录(1) - 环境搭建

268 阅读3分钟

新人前端,有不足之处请多多指教

本文是Electron实战系列的第一篇,主要介绍如何一步一步搭建自己的Electron开发环境,以及如何创建一个简单的Electron应用。

技术:electron、esbuild、Livereload、chokidar

环境:Node.js v20.18.1、electron v34.2.0、Windows 11

最基础的electron应用只需要一个主进程main.js和一个渲染进程index.html即可,但是为了更好的开发体验,我们还需要一些工具来辅助开发,比如热刷新、打包等。

在本文中,我们要完成以下几个目标:

  1. 主进程打包及监听重启
  2. 渲染进程打包及热刷新
  3. 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来实现。