永远正确 - 扩展迁移故事

我从 2005 年开始为 Firefox 构建扩展。我已经集成了书签服务(这让我在 Mozilla 找到了一份工作!),修复了默认主题,增强了开发工具,调整了 Github,优化了性能,简化了标签操作,为所有 Etherpads 添加了书签,修复了 Pocket 以及许多其他 糟糕的奇妙事物

我已经编写了 XUL 扩展、Jetpacks、Jetpacks(第二种)、SDK 加载项,并且还参与了其中大部分的核心开发。现在我已经见过所有的一切:Firefox 有了 WebExtensions API,一种新的扩展格式,旨在实现浏览器扩展性,而不会牺牲性能和安全性。

在 Firefox 57 中,WebExtensions API 将成为唯一支持的扩展格式。所以现在是时候继续前进了。我不能再沉迷于旧扩展格式允许的不安全的性能漏洞 API 的奢华中。是时候迁移我无法忍受没有的扩展了。

我从 Always Right 开始,这是我最常用的浏览器扩展之一。我记录了这次迁移,包括 hiccups、失误和折衷方案。希望这能帮助你在扩展迁移之旅中!

我是 Always Right

Always Right 是一个简单的 Firefox 扩展,它将所有新标签立即打开在当前标签的右侧,无论标签是如何打开的。

这很棒,原因有二:

  • 标签打开行为可预测 - 它始终保持一致。Firefox 中的默认行为取决于许多因素,过于复杂,这里无法一一列举。我只想说,改变 Firefox 的默认标签打开行为就像在飓风中追逐黄蜂。

  • 相关标签分组。当我思考我正在做的事情,并想要开始新的搜索或打开与之相关的标签时,我会打开一个新标签。这个附加组件确保该标签与当前标签分组。默认行为会在标签栏的末尾打开该标签,这会导致两个不同的标签组,它们都与同一任务相关。

从概念上讲,Always Right 是一个简单的扩展,但最终需要完全重写才能迁移到新的 WebExtensions API 格式。大多数重写工作都很轻松且快速,但正如我们作为开发人员所面临的困扰,最后的几部分花费了最长的时间,并且极其令人沮丧。

迁移概述

总体概念没有改变:使用新 API 构建的扩展仍然是一个包含清单文件以及所有代码和资产文件的 zip 文件,就像之前的所有其他扩展格式一样。

迁移的主要部分是:

  • 重命名并迁移到新的清单格式。
  • 重写代码以使用新的 WebExtensions API。
  • 使用新的 web-ext CLI 工具进行打包。

迁移清单

第一步是迁移你的清单文件,首先将 package.json 重命名为 manifest.json

以下是一张图片,显示了旧文件和新文件之间的差异

最重要的更改是添加属性 manifest_version 并将其值设置为 2。有了 manifest_versionnameversion 字段,你现在就拥有了有效扩展所需的所有必备属性。其他所有属性都是可选的。

但是,由于你要更新一个已经存在的扩展,因此还需要做几件事。

  • id 属性对于 addons.mozilla.org (AMO) 来说是必需的,以便将新的加载项与旧的加载项匹配。删除顶层 id 字段,并将它的值复制到 applications/gecko/id 字段中。

  • 如果你使用了 main 属性,现在可以通过特定功能来指定你的入口点文件,例如 后台脚本内容脚本浏览器操作(工具栏按钮)页面操作选项 UI。在我的扩展中,我需要监听标签事件,所以我使用了后台属性来加载脚本。

  • permissions 属性被使用,但方式不同。值现在是一个数组而不是一个对象,你拥有的任何值可能不再受支持,需要进行替换。你可以在 MDN 上的 manifest.json 权限页面 上阅读有关支持的权限键和值。

这里没有介绍更多可选字段。阅读 新的 manifest.json 文档 中有关其他字段的信息,以及旧的 package.json 文档

迁移功能

Always Right 的流程是监听一个事件,该事件指定一个新标签已打开,然后修改该标签的索引,使其位于当前活动标签的右侧。

我首先将我的 /lib/main.js 文件移到 /index.js,并在 manifest.json 文件中将其指定为后台脚本,如上所述。

然后,我将 /index.js 中的代码从旧的 SDK 标签 API 迁移到 WebExtensions 标签 API。旧的 SDK 代码使用了 tabs.open 事件,而新的代码使用了 WebExtensions tabs.onCreated 事件

例如,这个:

window.tabs.on('open', function(newTab) {
    // do stuff
});

变成了这个:

browser.tabs.onCreated.addListener(function(newTab) {
    // do stuff
});

另一个更有趣的转换是如何获取对当前活动标签的访问权限。

在 SDK 中,你可以简单地访问 window.tabs.activeTab,但在新的扩展世界中,你需要这样做:

browser.tabs.query({currentWindow: true, active: true}).then(function(tabs) {
    // do stuff with the active tab
    var activeTab = tabs[0];
});

这些是主要更改。应用程序逻辑和代码流与之前几乎相同。但是,由于这是一个具有不同行为的新 API,因此出现了一些问题。我不得不进行以下调整:

  • WebExtensions API 代码在活动标签可检索之前初始化,因此我需要添加对活动标签的检查,如果它还不可用,则执行无操作。

  • SDK 标签 API 在用户重新打开之前关闭的标签时不会触发,但 WebExtensions API 会触发。因此我不得不添加检查以确保我不重新定位这些标签。

  • 另一个行为变化是,将标签放置在非最后一个固定标签的固定标签旁边会将它放在标签栏的末尾,而不是像 SDK API 所做的那样只将它放在固定标签的末尾。因此现在我获取所有标签并遍历它们,直到找到最后一个固定标签,然后手动将该标签放置在那里。

我还必须提供一些不太理想且目前无法修复的行为:

  • WebExtensions API 在标签添加到标签栏后执行 tabs.onCreated 监听器。这意味着,使用 Always Right,如果你有很多标签(比如,数百个),你实际上可以观察到标签被添加到标签栏的末端,然后快速滑到活动标签的右侧。这让人眼花缭乱。

  • 使上述问题更加严重的是,标签栏滚动到新标签,因此当前活动标签被滚动到视图之外。

测试和调试

在现有配置文件中进行测试的新的、改进的开发工作流程与 Firefox SDK 完全不同。

要安装你的加载项以进行测试,请打开一个新标签,导航到 about:debugging(参见下面的屏幕截图)。单击加载临时加载项按钮并选择你扩展源目录中的任何文件。你的扩展将被安装!

about:debugging screenshot

但如果你在那里看到错误呢?如果功能没有按预期工作呢?你可以使用浏览器工具箱来调试你的扩展。阅读此处了解如何配置和 打开工具箱

在开发过程的后期,我发现了 web-ext CLI,它非常棒。像使用 cfx/jpm 一样使用 web-ext run。它会在临时配置文件中打开。

发布

我的更改完成后并经过测试,我依靠我的新朋友 web-ext 并使用 web-ext build 打包了一个 zip 文件。zip 文件位于 web-ext-artifacts 子目录中,并使用新版本号命名。我像往常一样将文件上传到 addons.mozilla.org,并且扩展通过了验证。我等待不到一天,我的扩展就被审核并上线了!

胜利!好吧,不是完全的胜利:错误马上就来了。在用户们慷慨仁慈地帮助下,他们通过给加载项提供 5 星评级并在评论中指出新版本已损坏的方式来报告了这些错误。😅

我已经修复了大多数已报告的问题,所以我的用户和我都可以在夕阳下快乐地骑马了。

需要帮助?MDN 上有关于迁移加载项的详细文档,请查看 旧扩展移植页面

你可以在 Github 上的 Always Right 存储库 中查看此加载项的源代码。如果你发现更多错误,请告诉我!

如果你想试用这个扩展,可以从 addons.mozilla.org 安装 Always Right

参与

所有代码都在不断改进中,参与开发过程并报告错误是解决问题最简单的方法。如果你在 WebExtensions API 中遇到错误,请在 Bugzilla 中的 WebExtensions 组件 中提交错误报告。

我在迁移这个扩展时提交的错误:

关于 Dietrich Ayala

更多 Dietrich Ayala 的文章...


9 条评论

  1. wOxxOm

    nit: browser.tabs.query({currentWindow: true, active: true}) 会生成活动选项卡的完整选项卡对象,因此不需要嵌套的 browser.tabs.get

    2017 年 9 月 21 日 上午 8:31

    1. Dietrich Ayala

      谢谢!我将测试该更改,如果正确的话将更新代码示例!

      2017 年 9 月 21 日 下午 5:21

      1. Dietrich Ayala

        是的,它有效!非常感谢,我已经更新了文章。

        2017 年 9 月 21 日 下午 5:28

  2. Mark

    我喜欢从现在开始所有扩展程序都将使用单个 API 创建,但我有点担心现有扩展程序会发生什么。我目前使用的扩展程序中除一个之外,所有扩展程序都被标记为“Legacy”——Firefox 57 淘汰旧式扩展程序的时间是不是有点太早了?

    2017 年 9 月 21 日 上午 11:13

    1. Dietrich Ayala

      是的,对于传统的扩展程序作者来说,淘汰它们永远不会是*好的*时机。但是,由于这些 API 会导致安全、性能和稳定性问题,因此对于我们的用户和 Firefox 的未来来说,永远不会有*糟糕*的时间来做这件事。附加组件团队花了很长时间为社区准备这次迁移,虽然这对像我这样的人(有很多传统的扩展程序)来说很痛苦,但好处远远大于成本。

      2017 年 9 月 21 日 下午 5:23

  3. Jack

    你应该试试树形选项卡,它是一种管理新选项卡的更好的方式。

    “始终直接在右侧”这基本上是一个毫无意义的功能。就像井底的人终于看到有人往里看,只是想要一点盐给被迫吃的青蛙。要梯子,哈哈!

    2017 年 9 月 21 日 下午 12:23

    1. Dietrich Ayala

      嗯嗯,美味的咸青蛙!我喜欢树形选项卡,但对我来说,它解决的是不同的问题。始终在右侧将我的选项卡放在彼此的上下文中。树形选项卡使我更容易直观地扫描选项卡组。

      2017 年 9 月 21 日 下午 5:25

  4. steltenpower

    这也能在其他浏览器上运行吗?
    这就是新(对 Firefox 来说)API 的目的,不是吗?

    2017 年 10 月 3 日 下午 3:10

    1. Dietrich Ayala

      它应该能够在所有支持 Tabs API 的浏览器上运行。

      对我来说,跨浏览器兼容性不是采用 WebExtensions API 的*关键*点。我是一名 Firefox 用户,我一直主要开发 Firefox 扩展程序来满足自己的需求……如果其他人也喜欢这些扩展程序,那就太好了。我从未为任何其他浏览器发布过扩展程序,因为我不使用那些其他浏览器,除了测试 Web 内容或查看一些新功能(这非常罕见——如果你问我,浏览器陷入了选项卡的暴政中)。

      作为一名长期开发 Firefox 附加组件*和* Firefox 内核的开发者,我亲身经历了传统的扩展程序情况有多*糟糕*。对于这种架构来说,这始终是一个安全、稳定性和性能方面的噩梦。

      说实话,太糟糕了。性能陷阱。安全萨拉拉克陷阱。稳定性就像圣安德烈亚斯断层。

      2017 年 10 月 3 日 下午 9:25

本文评论已关闭。