调试电子:旅程

调试是开发中不可避免的一部分。 尽管程序员的陈规定型观念强调了出色的创新能力(好吧,陈规定型观念实际上是比萨饼和苏打水的马拉松比赛,但是对知识分子的强烈征服也占了很大一部分),但现实是我们的大部分工作实际上是艰苦的侦探工作:仔细检查密集的代码行,以查找导致程序崩溃的一个错误。 当我回想起Dennis Nedry在Jurassic Park中的两百万行代码时,我可能会有点约会,但是即使在很小的代码库中,调试也要花费时间和精力。 当人们正在学习诸如Electron之类的新框架时,尤其如此,它本身仍然是一种新兴技术。

正如我在介绍Electron时所指出的那样,该技术允许开发人员使用JavaScript,HTML和CSS编写Windows,macOS和Linux桌面应用程序,然后将其编译为本地代码。 这是一个很大的便利,但是它也有一些缺点。 正如我们(我的同事Ian Lancaster和Alex Pilewski和我)最近发现的那样,当我们接近完成我们正在构建的名为Fired Up的生产力应用程序时,其中之一就是高水平的抽象有时会使调试特别困难。 错误是否来自我们编写的代码,npm软件包,Apple Script,Windows代码……? 这是当今精选错误的核心。

如我之前的文章中所述,我们的应用程序是一种生产力工具,可以监视用户对桌面应用程序的使用情况。 它包括一个带有此数据的菜单栏窗口以及一个允许用户控制和查看会话的UI。 我们的错误源于以下事实:每当用户关闭程序(“ Fired Up”本身除外)时,我们的程序就会崩溃,并且错误消息将反复闪烁。 这些消息是程序员最讨厌的无用信息:“ JavaScript错误:未定义:未定义。”第二条错误消息被证明是更有帮助的,因为它向我们指出了一个特定的功能,但是我们仍在摸索着很长时间。

我们首先查看了所讨论的函数,该函数负责将代表最新用户会话的对象发送给渲染器(有关我在Electron中对renderer与main的讨论,请参阅我的先前帖子)。 我们在主文件中搜索了逻辑,错别字等方面的任何失误,但是尽管我们尝试了很多,但仍无法查明问题所在。

一段时间以来,我们唯一的面包屑将我们指向包含该应用程序的窗口。 Electron有一个内置的BrowserWindow对象,它提供应用程序的窗口,还有一个我们正在拉入的npm库,菜单栏,为BrowserWindow提供了包装器。 因为我们的主要错误是告诉我们指向菜单栏的变量未定义,所以我们的第一步是向相关函数添加条件,告诉它们仅在存在menubar / BrowserWindow的情况下才执行相关代码。 我们希望这可以解决问题,但是,,,不是。 无论我们如何包装函数,错误消息都会不断触发。

然后,我们在Internet上搜索了与Electron,菜单栏和活动窗口(我们正在使用的另一个库)相关的任何文档和已记录的问题。这花了很长时间才能取得成果,但是Ian最终发现,嵌入在主动窗口代码可能是罪魁祸首。 经过进一步检查,我们发现当用户关闭应用程序窗口时,Apple Script会不断抛出错误。 由于不熟悉Apple Script,我们试图找到一种编写它的方法,最终我们找到了解决方法:将激活Apple Script错误消息的JavaScript代码包装在活动窗口模块的索引中。如果用户使用Mac,则条件文件中的js文件会忽略其内容。 我们的代码如下所示:

 如果(process.platform =='linux'|| process.platform =='win32'){ 
ls.stderr.on(“ data”,function(stderr){
抛出stderr.toString();
});
}

瞧! 没错 我们的代码甚至可以在Linux上运行,而无需任何其他填充。 我们仍然需要在Windows上测试我们的代码,但是这种解决方法解决了Mac的烦人问题。

我们的应用程序可在Ubuntu中使用!

但是,我们确实遇到了最后一个问题:如何将修改后的活动窗口代码添加到应用程序中,因为节点模块没有(也不应被)推送到我们在Github上的仓库中。 我们发现可以将包含修改的活动窗口代码移到应用程序中的vendors文件中(该文件不会被gitignored),然后将其移入主文件中。 当我们需要为以后的应用程序修改npm包中的代码时,此技巧肯定会有用。

我们从这种调试经验中学到了很多东西。 事实证明,在某些情况下,调试Electron可能需要比其他框架更多的步骤,但是经过一些挖掘和毅力,仍然可以解决问题。