除非你在过去5年里一直生活在岩石下,否则你有可能使用过电子巴......。

除非你在过去5年中一直生活在岩石下,否则你有可能在你的生活中至少使用过一次基于电子的应用程序。对于那些不知道Electron是什么的人(可能很少),它是一个建立在Chromium和NodeJS之上的跨平台桌面应用框架(NodeJS又是基于Chrome的V8引擎)。这个Chrome-ception允许开发者使用网络技术建立完整的桌面应用程序,包括HTML、CSS、JS和我们都知道并喜爱的~500MB的node_modules。

玩笑归玩笑,Electron提供了几个好处,使它成为当今大多数桌面应用程序开发的首选,包括。

  • 真正的免费和开放源代码
  • 一次编码,在Windows、macOS和Linux上部署
  • 在丰富的用户界面方面有无限的灵活性
  • 广泛的应用
  • 尽管如此,Electron经常受到大量的批评,尤其是在开发者中。我自己在专业和娱乐方面都从事了几年的桌面开发工作,我喜欢阅读关于这个话题的讨论,并尝试不同的方法。随着时间的推移,我形成了这样的想法:Electron是一种必要的邪恶,在许多使用情况下,它(令人惊讶地)优于其他的选择。

    这篇文章就是要讨论你可以用来创建跨平台应用程序的不同方法,以及它们的优点和缺点。最终,你将对不同的替代方案及其理想的使用情况有一个基本了解。也许,到最后,你会同意我的观点。Electron并不是那么糟糕。

    在跳到各种替代方案之前,我们首先需要定义人们通常抱怨的Electron的主要缺点。

    高内存消耗 。Electron的应用程序往往使用至少80MB的内存,轻量级的应用程序在130-250MB之间,而像Slack这样的怪物有时会达到数GB的数值。 大的存储足迹 。带着完整的Chromium运行时间,你可以预期大多数Electron应用程序会消耗至少150MB的存储空间。 缓慢 。一些Electron应用程序肯定很慢,但这可能取决于许多因素。例如,过度使用动画会大大增加CPU的使用率,从而使应用程序感觉更慢。你是否注意到,大多数感觉敏捷的桌面应用程序都不包括任何动画?仅仅因为你可以用Electron,并不意味着你应该用。 缺乏本地UI/UX 。Electron渲染的是网页而不是本地控件。一方面,这给了设计师完全的自由,但另一方面,应用程序看起来与 "本地 "的不同。不出所料,这种抱怨通常来自于macOS的用户,那里只有一个 "原生 "框架。Cocoa。由于其他平台(尤其是Windows)上GUI框架的分散性,非macOS用户通常对应用程序不共享相同的外观和感觉更加宽容。 安全性较差 。与在你的网页浏览器上运行的普通网站相比,由于NodeJS的集成,Electron的应用程序令人难以置信地更加强大(和危险)。如果配置不当,在Electron内部运行的网页可以获得对整个系统的访问,这在显示第三方网站时尤其危险。幸运的是,不必如此,因为Electron提供了 Context Isolation 来屏蔽渲染器与NodeJS APIs。此外,有些人认为,NPM生态系统的安全性不如其他同行。

    考虑到这些,让我们看看其他的方法与Electron相比如何。

    跨平台核心,原生UI

    这种方法通常被认为是跨平台开发的黄金标准,它包括在一个库中提取应用程序的业务逻辑(通常用低级和跨平台的语言如C++或Rust编写),然后为每个平台编写一个单独的GUI,利用本地框架。由此产生的应用程序速度快,重量轻,并且具有真实的外观和感觉。

    如果效果这么好,为什么不是每个人都采用这种方法呢?嗯,事实证明,从开发的角度来看,这种方法是非常昂贵的。你不仅要实现N个不同的UI(这已经不是小事了,因为你必须学习3个不同的本地框架,还有它们的怪癖),而且这些低级语言和UI之间的互操作性也不尽人意。简而言之。

  • 每一个对GUI有影响的功能,都要花N倍的时间来实现。
  • 与底层库的互操作性并不总是方便的,特别是当你开始处理字符串或动态分配的内存时。谁来释放这些内存?这是一个你会经常问自己的问题。此外,答案取决于当前的平台,因为有些平台使用垃圾收集,有些平台使用引用计数,有些平台使用手动管理。
  • 那么......我们应该摒弃这个选项吗?不,不一定。如果你的应用程序的大部分复杂性都与业务逻辑有关,而且用户界面很简单,那么这种方法可能是绝对可行的(甚至可以说是首选)。我遇到的一个例子是Backblaze的客户端用户界面,根据 这篇旧文章 ,它采用了这种方法。这很有意义,因为用户界面本身相当简单,只由几个按钮和标签组成。

    另一方面,如果用户界面相当复杂或者包含自定义组件,选择Electron通常是一个不错的选择。有些人肯定会争辩说,你不 "需要 "自定义组件,那么代码编辑器呢?你认为像VSCode这样复杂和灵活的东西,用本地控件是否可行?老实说,我不这么认为。

    从同样的前提出发,我个人喜欢的中间方法是wxWidgets,这是一个成熟的库,使开发者能够从单一的C++代码库中创建跨平台的应用程序。我特别喜欢wxWidgets的一点是,它尽可能地使用本地小部件。对于 简单的 用户界面来说,所产生的应用程序是快速的、轻量级的,而且看起来很棒。

    这是我个人在 modulo 中使用的方法,这是 espanso 的一个轻量级图形扩展,我用Rust实现了业务逻辑,用C++实现了UI代码。

    同样,我只考虑对简单的UI采用这种方法,因为这有很大的开发开销。此外,随着用户界面变得越来越复杂,所产生的应用程序与原生的应用程序相比,看起来越来越 "不对劲"。

    "只要使用QT,它比Electron好得多!"

    如果你浏览一下关于新发布的Electron应用程序的讨论,保证会出现这种评论。简而言之,QT是一个跨平台的应用开发框架,在几年前特别流行。使用QT,你可以从一个单一的C++代码库中支持3个主要的平台,或者如果你不喜欢这种语言,很有可能存在一些与你喜欢的语言的绑定(特别是Python)。

    用QT制作的应用程序通常不那么耗费资源,而且速度更快(当使用C++时),但有多快呢?

    以我最喜欢的QT应用程序Telegram Desktop为参考,我们可以看到。

  • 它使用了130MB的内存
  • 它占用了70.8MB的存储空间
  • 作为参考,以下是一个可比较的Electron应用程序Whatsapp Desktop的数值。

  • 254 MB的内存
  • 450 MB的存储空间(我知道这是一个很大的数字,但这是WhatsApp的错,而不是Electron的。我每天使用的许多Electron应用程序,如Bitwarden和Obsidian,使用~170 MB)
  • 正如你所看到的,QT的对应程序通常要消耗大约一半的资源。但这值得吗?

    在一个拥有8GB内存的系统中,这在今天是很常见的,250MB的内存大约占总内存的3%。对于短时运行的应用程序来说,可以说这个数字几乎是微不足道的。当然,不是所有人都会同意这一点。

    同时,选择QT意味着接受一些不太理想的妥协,其中最重要的是许可证。QT是双许可证:你可以选择开源许可证,也可以选择商业许可证(剧透一下,准备在这个上面花几千美元)。如果你正在创建一个开源项目,那么你很幸运,只要你以GPL方式发布你的代码,QT就可以免费使用(尽管最近有一些 争议 )。但是,如果你是一个希望发布商业软件的小型软件公司呢?也许有机会动态链接LGPL版本,避免支付完整的许可证,但这并不总是可能的。我相信有些人会不同意,但我认为QT只对开源项目或大型企业是一个可行的选择,一切介于两者之间的东西在经济上都不会有持续性。

    此外,尽管QT试图类似于平台的外观和感觉,但你绝对可以看出一些问题。只要看看 DB Browser for SQLite 的macOS版本(我认为这是一个伟大的软件,我只是指出 "外观和感觉 "是如何的不对)。

    考虑到一个写得很好的Electron应用程序将使用两倍于同等的QT对应程序的资源,它真的值得吗?只有你能回答这个问题,但说实话,我不认为收益(或者更好的是节省的资源)足以让你放弃Electron。

    本地主机服务器

    对于长期运行的进程,另一种常见的方法是在用户的浏览器中提供一个网络GUI,连接到一个仅有本地主机的HTTP服务器。这种解决方案目前被 Syncthing Jupyter Notebook 所采用,它与Electron在丰富的用户界面方面有许多相同的优点,同时又非常轻巧(不需要捆绑整个Chromium运行时间)。尽管如此,还是有两个主要的缺点。

  • 与操作系统的整合不太理想,因为图形用户界面将以网站而不是应用程序的形式出现。这也意味着没有菜单栏,比如说。
  • 不能控制用户的浏览器,这意味着必须支持广泛不同的渲染行为。公平地说,只要你不致力于支持IE,或者你需要一些花哨的新功能,这个问题就会变得越来越不重要。
  • 尽管我认为这种方法在很多情况下是可行的,但我认为它远不是最佳方法。我知道这很主观,但我真的很欣赏为每个应用程序提供一个单独的窗口,以及良好的操作系统集成,如本地菜单栏和对话框。

    嵌入系统的webview

    对Electron的一个通常的抱怨是,每个应用程序都有一个单独的Chromium运行时,每个应用程序浪费了大约100/200MB的存储空间。一个自然的问题出现了。为什么不把这个运行时间提取成一个单一的、全系统的模块,然后在所有的应用程序之间共享(类似于JVM)?鉴于大多数操作系统都有一个可嵌入的webview组件,我们为什么不使用它而非单独的运行时呢?

    从纸面上看,这种方法听起来像是理想的解决方案:产生的二进制文件非常轻巧(几兆字节),并且仍然可以利用网络技术来创建丰富的、跨平台的用户接口。此外,直接的操作系统集成也是可能的,因为产生的程序可以从 "包装 "代码中访问本地设施(菜单栏、对话框等)。许多项目正试图用这种方法来克服Electron的缺点,例如 Electrino webview Tauri ,以及更多。

    许多个月以来,我认为这种方法比Electron优越,开发的便利性是唯一的缺点。你看,如果你选择这种方法,你将需要自己做很多 "管道",因为你不能使用Electron所暴露的任何方便的API。你想要一个菜单栏吗?你必须自己编写底层绑定,而且往往是多次编写,这取决于你希望支持的平台的数量。

    当时,我想为 espanso 创建一个图形用户界面,这似乎是试验这些技术的完美机会。我分叉了原来的webview项目(因为我想增加一些功能),并为Windows创建了第一个非常alpha的版本。

    正如预期的那样,实现业务逻辑比Electron更棘手,必须手动将C++、Rust和JavaScript混合在一起,但该应用程序非常轻巧,只消耗了 2MB的存储空间和 70MB的内存。听起来很成功吧?嗯,事实证明我忽略了一个关键的方面:兼容性。

    想象一下,建立一个依靠复杂库来执行核心功能的应用程序。这个库并不真正与你试图支持的所有平台兼容,所以你选择了这个库的一些本地端口,它们都大致符合一个共同的规范。唯一的 "坏处 "是你不能控制库的版本。结果发现这个库的Windows端口有一个错误,你该怎么办?即使在下一个库的版本中提供了修复,你也不能控制用户使用的版本。正如你可能已经理解的那样,这个 "复杂的库 "只不过是内嵌的webview而已。

    去年,情况更糟糕,因为Windows只支持不合格的webview。除了基于IE的,我只推荐给你最大的敌人,Windows还提供了基于Edge的,"有点 "体面,但绝对比macOS和Linux中的基于WebKit的差。幸运的是,随着新的基于Chromium的Edge浏览器的出现,Windows也将搭载一个现代的、可嵌入的webview,称为 WebView2

    正如我们之前所说,依赖一个你无法控制的组件是有风险的,因为版本是锁定的,其错误也是锁定的。这也是为什么像Slack这样的公司会放弃这种方法的部分原因(更多关于这个问题 这里 )。

    我们应该总是抛弃这种方法吗?当然不是。但我个人认为,只有当应用程序的复杂性相对较低时,才会考虑使用这种方法,特别是在涉及到样式设计时。

    值得一提的是

    另一个有前途的选择是 Sciter ,它使得使用HTML/CSS和任何支持C绑定的语言(大多数都支持)来创建非常轻量级和跨平台的应用程序成为可能。最大的缺点是,该引擎不是开源的,尽管它 将来可能会成为 。不要误会我的意思,我完全理解作者希望提供一个商业许可来资助其开发,但我倾向于在可能的情况下选择开源的替代品。

    这篇文章的目的并不是要证明Electron如何总是最好的选择(它并不是),而是要对它最适合的领域做一个广泛的概述。例如,你不应该把它用于具有简单UI的应用程序,或者如果你不需要跨平台。在这种情况下,选择本地框架很可能是最好的选择。也就是说,如果你需要跨平台,而且你的应用程序足够复杂,那么Electron与其他替代方案相比真的一点也不差,尤其是在做对的时候。当然,也有一些非常臃肿的Electron应用程序,我也不喜欢它们,但这主要是由于粗心的开发者,而不是Electron。

    最后,请记住,如果没有Electron,一些开发者可能无法管理跨平台开发的负担,因此,一些伟大的应用程序甚至可能不存在。这就是为什么我认为它是一种_必要的邪恶。

    如果你喜欢这篇文章,请在 Twitter Youtube 上关注我!

    www.deepl.com 翻译