logo

San DevTools 技术解析(上)

作者:九十九2021.01.05 00:18浏览量:312

简介:这是《San DevTools 技术解析》第一篇文章,重点介绍下 San DevTools 的主要功能、整体架构和重要的模块概念。

前言

今天我们带来《San DevTools 技术解析》上、中、下三篇系列话题,带大家深入理解 DevTools 底层原理,通过关键技术的讲解,理解 DevTools 底层设计原理,理解 San 与 DevTools 如何通信?Standalone 版本如何调试多种场景?WebSocket 通信如何实现?Chrome 插件应用到哪些技术?远程调试如何实现?调试协议有哪些有意思的应用场景等等。

San DevTools 整体涉及的技术点较多,希望通过本文大家能够理解掌握关键技术与设计。

这是《San DevTools 技术解析》第一篇文章,重点介绍下 San DevTools 的主要功能、整体架构和重要的模块概念。

PS:在 San DevTools 中我们集成了 Chrome DevTools,可以实现远程调试 Webview 页面,即使不是 San 用户,也可以使用该工具远程调试手机 / 模拟器中的页面,并且不需要安装 inspect 内核。是时候替换 vconsole 之类的调试工具了,来试试我们的 Chrome DevTools 远程调试吧!

整体介绍

功能简介

San DevTools 以两种方式存在:

  1. 通过 Chrome 插件商店 获取插件版本,具体参考使用文档

  2. 通过 Npm 安装独立的 Standalone 版本,增强远程调试功能, 集成 Chrome Devtools 的远程调试功能,方便的调试移动端页面,一般推荐使用;

Standalone 版本支持两种调试模式,如下视频演示:

  1. 针对 San 应用的远程调试模式;

  2. 适用任何环境的 Chrome 远程调试模式,支持移动端 H5、IE、Safari 等环境;

核心概念

San DevTools 是支持 San 应用开发的调试工具。

为了方便大家理解其中的概念,我们先思考如下的问题:

如何从零设计 & 实现一款远程调试工具?实现查看组件树功能。

首先,我们应该能想到需要有两个模块,一个是调试的工具,一个是被调试的目标页面。按照远程调试工具的传统,站在开发工具的角度,把工具页面叫做 Frontend,被调试的目标页面叫做 Backend,和传统前后端开发概念有点类似。

其次,前后端的通信问题要先考虑,如何设计方便前后端模块发送事件呢?参考前端与 NA 端桥接 Bridge 的概念,设计了 Bridge 实例,各模块内部通过实例方便地发送事件。

// Server
import WebSocket from 'ws';

const wss = new WebSocket.Server({port: 8080});

wss.on('connection', ws => {
     const bridge = new Bridge({
          listen(fn) {
               ws.on('message', fn);
          },
          send(data: any) {
               ws.send(data);
          }
     });
});

io.listen(8080);
// Backend/Frontend Bridge
const wss = new WebSocket('wss://localhost:8080');

const bridge = new Bridge({
     listen(fn) {
          wss.onmessage = fn;
     },
     send(data: any) {
          wss.send(data);
     }
});

再次我们思考几个问题:

  1. 前后端可不可以直接通信?

  2. 收集、计算 Backend 页面数据的模块如何设计?

  3. 格式要不要规范(类似 RESTFul 格式)?

对这几个问题分别进行分析:

  1. 通信协议大家直观能想到要用 WebSocket 技术,前后端其实都是跑在浏览器里的页面,显然不能直接通信,需要服务端做中间联接;

  2. 收集数据的模块需要监听、操作页面的 JS/Dom 等,这里用了非常形象的 Hook 概念与模块;计算处理数据的工作会比较多,比如组件树数据的计算生成,组件路径数据等等,这部分主要工作是代理 Frontend 与 Backend 之间数据的交互处理,所以有了 Agent 模块;

  3. 传统前后端开发会有 RestFul 风格接口、接口规范文档等,我们的 Backend 与 Frontend 同样需要一定的规范,这就是 Remote Debugging Protocol 协议规范,为了实现交互的标准规范;

  4. 在服务端需要建立对应的前后端消息联接,叫做 Message Channle 消息通道,或更形象点叫 房间,消息不可以在不同房间内『串门』,保证消息的准确性;

总结:通过本节的介绍我们明白了远程开发调试必备的四大核心模块:

  • Frontend:调试工具前端,在 Chrome DevTools 里包括我们经常看到的 Elements、Console、Network、Source 等面板;在 San DevTools 我们实现了 Component、History、Store、Event、Message 等面板;

  • Backend:调试器后端,注入到运行中的页面,从调试工具的角度看属于 Backend(稍注意下概念,和传统前端理解不太一致);

  • Protocol:调试协议,连接 Frontend 与 Backend 的交互协议,通过定义方法和事件提供双方的交互,包括相应的 JSON 数据格式;

  • Message Channel:消息通道,为实现 Frontend 与 Backend 的通信设计,包括 WebSocket Channel,Chrome Embedder Channel,Chrome Extensions Channel;

除四大核心概念外,为实现相应的功能引入三个概念与模块:

  1. Bridge:类似于前端与 NA 端建立的桥接,方便前后端发送消息通信;

  2. Hook:目标页面勾子,与调试的页面深入结合,可操作目标页面的 JS/DOM,并监听发出来的事件比如组件生命周期事件,主要功能是收集页面数据;

  3. Agent:目标页面的数据处理模块,数据来源为 HOOK 收集的数据或者通过 Bridge 接收到的数据,处理之后的数据会通过 Bridge 发送出去抑或存储在目标页面。

架构 & 流程

下面是 San DevTools 的整体架构图

整体流程如下图所示

Frontend & Backend

Frontend 与 Backend 有较多的交互流程,我们把这两个模块放在一起来说。

在不同的流程阶段,有不同的关键技术实现,我们分两个阶段进行说明。

初使化阶段

初使化阶段关键技术点:
  • Chrome 插件与 Standalone 版本,入口方面不同,Chrome 插件通过配置 manifest.json 实现入口,技术详情请参考本文的后续章节;

  • Standalone 版本会启动一个 Node 服务,提供 JS 文件,需要注入 JS 到调试的页面,实现页面数据的收集计算;

  • Hook 注入并劫持全局变量 __san_devtool__,所有和 San 框架相关的交互都是通过这个变量,比如 San 版本号等;具体可以直接通过控制台打印变量;

联接的建立:

  • 两次握手协议事件的发送,最终确认联接建立成功;

  • 核心是建立两个 Bridge 桥接实例;

  • 前后端的联接建立使用的是 WebSocket 或 Chrome Runtime 的长联接;

Standalone 功能更强大,支持任意页面的远程调试能力,与业界同类工具相比更优,比如 VConsole、Weinre 等:

  • 基于 Chrome DevTools Frontend 作为前端的调试面板,更符合前端同学的调试习惯,功能也更强大;

  • 适用于各种浏览器环境,比如移动端 H5 页面、IE、Safari、Native 等等;

其他节点阶段

这里我们以组件信息同步与组件树渲染两个阶段为例,这两阶段技术具有代表性:
  • DevTools 需要加载开发版 San (san.dev.js),才能支持调试工具;

  • San 通过 DevTools 注入的全局变量发送生命周期数据(其他数据也一样);

  • 组件树数据的生成是通过组件 attach 事件,在 Backend 页面记录并生成;同理大部分的数据收集与计算是在 Backend 实现的。

相关文章推荐

发表评论