Electron 入门 03 | 开发调试:如何基于 Electron 框架快速调试代码

3,597 阅读8分钟

你好,我是 Ben。前面我们已经学习了 Electron 的整体进程运行相关的流程,也了解了 Electron 的常用能力,相信你已经有能力自己上手做一个 demo 了。不过为了更加高效的开发,在正式动手开发之前,我们还需要熟悉一下 Electron 的调试方法,Electron 官网上关于调试的具体内容相对较少,也缺乏完整流程介绍,对于初学者来说很容易迷惑。本讲将详细介绍调试方法。

Electron 的渲染进程其实就是一个浏览器网页,因此也可以像 web 开发一样,在控制台中调试页面。而其主进程是没有对应的页面展示的,Electron 也提供了相关的调试方法。下面我们就分别来介绍渲染进程和主进程不同的调试方法。

渲染进程调试

渲染进程调试大体一般与我们特别熟悉与 web 浏览器一样,通过 Chrome 调试面板来操作。下面我们详细介绍一下。

Chrome 调试窗

我们在创建窗口实例后,调用 openDevTools 方法

// main.js
const win = createWindow(...);
win.webContents.openDevTools();

这样窗口打开时就会自动显示出如下图的调试窗,是不是特别熟悉!

image.png

我们看看多个窗口的效果,代码如下

// main.js
const win1 = createWindow(...);
win1.webContents.openDevTools();


const win2 = createWindow(...);
win2.webContents.openDevTools();

打开后效果如下

image.png

除了上面的代码启动调试窗外,我们还能在软件启动后,通过快捷键 Cmd+Option+I(或 Ctrl+Shift+I)来切换调试窗的显示。

另外我们还可以通过快捷键 Cmd+R(或 Ctrl+R)来直接刷新当前页面,以便我们快速验证页面而不是重启软件,前提是当前窗口是由焦点的,如果窗口是隐藏状态或者失焦状态,是不能通过快捷键触发调试的。需要注意的是这种刷新是不会刷新主进程的,也就是如果只是修改了渲染进程的代码,则可以通过这种方式来更新页面。

下面我们设置一个断点,然后刷新页面看看效果

image.png   扩展:VsCode 编辑器对应有一个插件 Debugger for Chrome 也可帮助调试渲染进程,感兴趣的可以了解了解。

Chrome 命令行开关

上面主要介绍的是独立窗口调试,那么对于嵌入在页面中的 webview 或者其他非独立子窗口,上面的方式将很不方便。而且如果有很多窗口,各自都打开一个调试窗也是很不优雅的。这里介绍一个非常实用的方法:Electron 支持的 Chrome 命令行开关。 参考下面代码

// main.js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315');

然后我们打开 Chrome 浏览器,输入 localhost:8351 将出现我们所有打开的窗口的列表。根据不同标题点击进入对应的窗口调试界面就可以了,甚至连隐藏窗口也可以调试,相当方便。当然这里的端口可以修改。

image.png

主进程调试

主进程和渲染进程不一样的就是没有可视界面,它只是一个 JS 文件的执行过程,所以调试主进程其实就是跟踪一个 JS 文件的执行过程,下面我们分别介绍通过 VsCode 和 Chome 面板两种调试方法。

通过 VsCode 调试

首先我们先给 VsCode 配置一个文件,点击 VsCode 左侧的 debug,然后点击新建一个 launch.json 文件。如下图操作

image.png

然后 VsCode 就会自动创建一个 lanuch.json 文件,里面有部分配置字段,我们需要改一下配置,或者点击右下角的添加配置,然后选择 Electron Main 来自动生成配置内容。

image.png

不管自己配置或者自动添加,最终我们生成的核心内容如下。其中 program 表示我们要调试的程序入口;runtimeExecutable 表示运行时获取 Electron 的目录;name 表示调试的名称。

image.png

这个时候在 VsCode 左上角下拉列表里就会显示出 Electron Main 这个调试名称,我们可以点击绿色箭头,就会运行主进程调试模式,我们可以通过 debugger 或者 VsCode 编辑器上行号来设置断点。

image.png

我们给主进程 main.js 设置断点,然后运行看看效果。

image.png

注意,主进程这里调试的是开发的文件,如果将运行入口文件指向 dist 的编译后的文件,则断点没法生效,不过其实 Electron 主进程本来就是基于 nodejs 的,不会有 web 端的兼容性问题,所以我们可以考虑不对 main.js 进行 es5 webpack 转换,只是简单的拷贝到 dist 下,这样也是可以正常运行的。

另外就是这里调试的是 js 文件,所以在所有断点运行完成之后,界面不一定能看到渲染进程的页面。

其实 Electron 主进程本身是一个 Nodejs 进程,所以这里启动调试时,我们在左上角不一定非得选择 Electron Main 这一项,也可以选择 Node.js 这一项,然后调用我们的 npm start 执行来运行调试。

image.png

通过 Chrome 调试面板调试

现在我们接着介绍一下 Electron 给提供的另一种调试主进程的方法或者说是基于 Nodejs 的能力,此方法将更加友好一些,而且没有上一种方法的缺陷,Electron 官网上并没有做过多的详细介绍,因为它其实算是 Nodejs 的调试。

在 package.json 的启动命令中加上参 --inspect,然后运行 npm start。

image.png

这时调试器已经启动了,此时我们在 Chrome 浏览器中输入 chrome://inspect,就会出现刚启动的 Electron 进程。

image.png

点击 inspect 后就会打开调试面板。

image.png

从运行日志其实可以看到,这里是监听了一个长连接的端口,用于调试 Nodejs 应用,这里我们没有写端口,默认端口就是 9229,因此我们可以自己修改端口,如--inspect=5858,这样可以实现多个应用的调试。

image.png

目前虽然能出现主进程的 Chrome 调试面板,不过程序已经执行完成,如何让程序断点执行呢,我们只需要将 --inspect 修改为 --inspect-brk。这样程序运行时,会在第一行暂停,然后就可以任意设置断点和调试了。实际效果如下。

image.png

需要提醒一点,因为这里程序暂停在第一行,所以运行时界面没有任何效果,不要以为程序卡住了,只需要去 Chrome 调试控制台进行控制就行了,并且这时我们可以在其他行设置断点,重启应用后,之前的断点将依然生效。

生产环境调试

因为 Electron 最终是一个安装包安装在用户的电脑上,那么如果需要排查线上包的某个问题的话,就需要考虑为我们的软件预留线上调试入口,但是这个入口又不能太轻易触发。也就是开发人员能够通过某种方式打开正式包的调试面板,从而帮助排查问题。

这里一般较简单的方式就是,我们在主进程中注册一个复杂一点的快捷键执行 openDevT,用来触发 DevTools 调试面板的打开。但实际项目中,我们采取了另一种更加可控的方式,那就是通过检测本地安装目录下是否存在某个文件来决定是否打开调试面板。

比如,我们手动在安装路径下新增一个名叫 dev-mode 的文件,重启 Electron 应用,就弹出调试面板,这种方式还可以用于生产环境和测试环境的快速切换,比如我们想把生产环境的包指向测试环境的接口,就可以通过这种方式快速切换,好处就是可以让测试团队快速验证问题。

参考如下局部代码

// main.js
// 储存你应用程序设置文件的文件夹
const devToolPath = app.getPath('userData'); 
const fs = require('fs');


if (fs.existsSync(devToolPath + '/dev-mode.txt')) {
  win.webContents.openDevTools(); // 打开调试面板
}
if (fs.existsSync(devToolPath + '/test-mode.txt')) {
  // TODO 将 api 请求指向测试环境
}

总结

本文介绍了 Electron 开发主进程和渲染进程最常用的调试方法,通过本节学习,可以帮助我们快速开发和调试 Electron 应用,不用去网上搜寻零散的资料。一个优秀的程序员的能力我觉得最重要的不是开发能力,而是调试程序和排查问题的能力。掌握正确的调试方法,形成解决疑难问题的逻辑思维,是提升技术实力的重要过程!

Electron 本身是一个 Nodejs 应用,能够和我们的本地文件系统及其他系统功能进行强交互,所以我们不管在测试还是开发方面,都要跳出 web 开发的浏览器思路局限,遇到一些问题时,借助 Electron 的能力,多思考一下更高效更惊艳的方案。

思考

对于生产环境的调试和问题排查还可能有哪些方便的手段呢?