分类: 技术

Chrome devtools 扩展与模块间通信

1. 背景

为了方便 Cyra 用户查看/管理项目中的视图及视图间的跳转和数据传递,决定开发一个 Chrome extension(扩展)来方便展示。开发中,最关键的问题在于如何解决各模块之间的通信。最终的实现效果如下图:

Cyra devtools

2. 开发

2.1 模块划分

这部分网上已经有很多文章来介绍,在此不再赘述。但网上涉及到devtools类型的插件比较少,所以简单介绍下。首先,在 devtools 中创建的 panel 本质是一个 HTML 页面。代码主要分为以下4部分:

  1. background.js:Chrome 为扩展提供的一个独立的脚本运行环境,在本例中,主要作为 content_script.js 和 devtools.js 之间通信的桥梁,因为 Chrome 并没有提供后面二者直接通信的服务。
  2. content_script.js:用来向打开的页面注入脚本。
  3. devtools.js:用来在 devtools 中创建一个 panel,并实现该 panel 和 background.js 之间的通信。
  4. draw.js:devtools.js 中创建 panel 所引用的页面脚本,本例中用来绘制状态。

下文为方便描述,不再添加 .js 后缀,直接使用模块名指代该模块。

2.2 事件注册(content_script)

为了动态显示项目中的所有视图信息和视图间的跳转(包括强数据传递),需要 Cyra 框架和扩展之间能够进行通信。所以考虑采用 pub-sub 模式,打开一个页面时,脚本动态向 window 对象上挂在一个简单的事件处理器,并且监听指定事件;当 Cyra 项目启动时,自动触发绘制视图的事件,从而执行事件处理函数向 devtools(以 background 为桥梁)发送信息,并绘制视图信息。

而 2.1 中已经说明,注入代码的工作应该由 content_script 来执行,所以它的工作主要就是实现一个简单的事件管理器,监听事件,并将代码注入到页面中。代码如下:

如此,当进入一个页面时,扩展会自动向该页面注入上面的脚本,然后在 Cyra 框架中初始化路由,以及执行页面跳转时,触发window.__CYRA_DEVTOOLS_GLOBAL_HOOK__对象上注册的相应事件,即可发送信息给扩展,剩下的由下一步处理。这里有以下两点需要注意:

  • 处于安全考虑,Chrome 规定 content_script 只能访问页面的 DOM,而不能访问它的 JavaScript 运行环境。所以只能动态添加 script 标签的形式向页面中插入一段脚本字符串。

  • 插入的脚本和 content_script 之间本质和上一点中提及的一样,也是两个执行环境,所以需要用window.postMessage来进行通信。

2.3 传递(缓存)事件

由于 content_script 和 devtools 之间无法直接通信,所以以 background 为中介。content_script 和 background 之间的通信只需要使用chrome.runtime.sendMessage即可,如上述代码中那样。但 background 和 devtools 之间也没有直接通信的 API 可供调用,官方给出的办法是在二者之间创建一个长连接保持通信,代码如下:

代码对应的 API 在官方文档可以直接查到用法,background 的主要工作除了保持与另两个模块的通信,还负责缓存事件。当进入一个页面,但还没有打开开发者工具时,先将事件缓存。待开发者工具打开后,devtools 会主动向 background 发起长连接创建请求,然后 background 会自动将缓存过的事件依次模拟触发一遍,使得 devtools 知悉哪些事件被触发。

2.4 绘制视图和跳转(draw)

最后一步,devtools 得到 content_script 经 background 传递来的信息后,会在 devtools 创建的 panel.html 中绘制相应的 SVG 图片。这里没有采用 canvas 主要是因为 SVG 也有文档模型,可以在上面绑定事件。具体代码如下:

当然,最后还添加了一点动画效果。扩展已经发布到了 Chrome App Store:Cyra devtools

3. 总结

这次开发主要了解了下 Chrome 扩展各模块的作用和他们之间的通信方式,并且在最后学习了下 SVG 的一些绘制方法,挺有意思。当然,扩展还有很多地方没有做到,后续会持续迭代。

注:转载注明出处并联系作者,本文链接:https://nodefe.com/chrome-extension-cyra-devtools/

发表评论

评论

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax