编程式调试node程序的利器chrome-remote-interface

简介

chrome-remote-interface是chrome调试协议的第三方调试客户端实现,该项目开源,提供了命令行工具,且为node程序提供了api。
chrome-remote-interface为基于chrome调试协议编写自己的node调试工具提供了便捷的途径,因为利用它,你不需要基于原始的协议通过websocket编程去开发调试工具了。
项目地址https://github.com/cyrus-and/chrome-remote-interface。

使用命令行

安装

通过npm进行安装

npm install chrome-remote-interface

启动调试目标

chrome-remote-interface基于chrome调试协议,因此其支持调试chrome浏览器和node运行环境。
无论哪种调试目标,其启动时都应该指定调试端口。
如果要调试chrome浏览器,应该在启动chrome时添加--remote-debugging-port参数,如下:

goole-chrome --remote-debugging-port=9222

如果调试node,在启动时添加--inspect参数,如下:

node --inspect=9222 app.js

此时,node会输出:

Debugger listening on port 9222.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
    chrome-devtools://devtools/remote/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9222/2894362d-f2d1-4f3b-a9e8-4e27da5714ef

题外话:如果只是希望调试node,并不打算开发一个调试node的工具的话,根据提示中的url,在chrome中打开就直接可以用chrome的开发工具调试了。

体验命令行

  • 查看全部命令

    在终端输入chrome-remote-interface并回车,可看到如下输出:

Usage: chrome-remote-interface [options] [command]

Commands:

inspect [options] [] inspect a target (defaults to the current tab)
list                   list all the available tabs
new []            create a new tab
activate           activate a tab by id
close              close a tab by id
version                show the browser version
protocol [options]     show the currently available protocol descriptor

Options:

-h, --help         output usage information
-t, --host   HTTP frontend host
-p, --port   HTTP frontend port
```

其中,new和close是针对浏览器的tab的命令,不要针对node来运行。
  • 查看所有页面实例

    chrome-remote-interface -t 127.0.0.1 -p 9222 list

    输出如下:

    [ { description: 'node.js instance',
    devtoolsFrontendUrl: 'https://chrome-devtools-frontend.appspot.com/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9222/2894362d-f2d1-4f3b-a9e8-4e27da5714ef',
    faviconUrl: 'https://nodejs.org/static/favicon.ico',
    id: '2894362d-f2d1-4f3b-a9e8-4e27da5714ef',
    title: 'app.js',
    type: 'node',
    url: 'file:///Users/renbaogang/git/enzyme.node/app.js',
    webSocketDebuggerUrl: 'ws://localhost:9222/2894362d-f2d1-4f3b-a9e8-4e27da5714ef' } ]
    

    其中devtoolsFrontendUrl可以在chrome地址栏中回车该url,打开chrome的开发工具,可以直接用该工具调试。和启动node时,node提示的url是一个用途。
    id是当前页面标识。
    url是当前页面url。
    webSocketDebuggerUrl是node提供的ws协议的调试服务,调试客户端需要通过该url连接到调试服务。

  • 查看调试目标版本

    chrome-remote-interface -t 127.0.0.1 -p 9222 version

    输出:

    [ { Browser: 'node.js/v7.0.0', 'Protocol-Version': '1.1' } ]
    
  • 查看调试目标支持的调试协议

    chrome-remote-interface -t 127.0.0.1 -p 9222 protocol

    输出:

    { 
    remote: false,
    descriptor: {
        { version: { major: '1', minor: '2' },
        domains:[略]
    }
    }
    

    remote:false说明协议内容是工具自带的协议文件,并不是来自调试目标。
    如果要获取调试目标的协议内容要添加-r选项,如:

    chrome-remote-interface -t 127.0.0.1 -p 9222 protocol -r

    输出:

    { 
    remote: true,
    descriptor: {
        { version: { major: '1', minor: '1' },
        domains:[略]
    }
    }
    
  • 调试命令

    chrome-remote-interface -t 127.0.0.1 -p 9222 inspect -r
    -r 表示应用调试目标提供的协议描述文件
    通过inspect可以调试node或chrome所支持的各个域。

    Console域体验

Console.enable()
{ result: {} }
Console.clearMessages()
{ result: {} }
```

Debugger域体验

```

Debugger.enable()
{ result: {} }
Debugger.setBreakpointsActive({active:true})
{ result: {} }
```

HeapProfiler域体验

```

HeapProfiler.enable()
{ result: {} }
HeapProfiler.startTrackingHeapObjects({trackAllocations:true})
{ result: {} }
```

Profiler域体验

```

Profiler.enable()
{ result: {} }
Profiler.start()
{ result: {} }
Profiler.stop()
{ result:
{ profile:
{ nodes:
[ { id: 1,
callFrame:
{ functionName: '(root)',
scriptId: '0',
url: '',
lineNumber: -1,
columnNumber: -1 },
hitCount: 0,
children: [ 2 ] },
...

      ]
    }
 }

}
```

Runtime域体验  
>>> Runtime.evaluate({expression:"1+1"})
{ result: { result: { type: 'number', value: 2, description: '2' } } }

Schema域体验

>>> Schema.getDomains()
{ result: 
   { domains: 
      [ { name: 'Runtime', version: '1.1' },
        { name: 'Debugger', version: '1.1' },
        { name: 'Profiler', version: '1.1' },
        { name: 'HeapProfiler', version: '1.1' },
        { name: 'Schema', version: '1.1' } ] } }
    ```
    
    体验事件处理
    
    scriptParsed是Debugger域提供的脚本解析事件
    
    ```
>>> Debugger.scriptParsed(params=>params.url)
{ 'Debugger.scriptParsed': 'params=>params.url' }
{ 'Debugger.scriptParsed': '' }
{ 'Debugger.scriptParsed': '/Users/renbaogang/git/enzyme.node/node_modules/negotiator/lib/encoding.js' }
    ```
    
## API ##
1. module([options], [callback])

    基于chrome调试协议连接调试目标
    
    options object类型,具有如下属性:  
    - host 默认localhost
    - port 默认9222
    - chooseTab 决定调试哪个tab。该参数可以为三种类型:
        - function 提供一个返回tab序号的函数
        - object 正如new 和 list返回的对象一样
        - string websocket url
        默认为一个函数,返回当前激活状态的tab的序号,如:function(tabs){return 0;}
    - protocol 协议描述符,默认由remote选项来定是否使用调试目标提供的协议描述符
    - remote 默认false,如果protocol设置了,该选项不会起作用
    
  callback   
    如果callback是函数类型,则该函数在connect事件发生后会得到回调,并返回EventEmitter对象,如果不是,则返回Promise对象。
    
    EventEmitter对象支持如下事件:  
    
    - connect
    
        ```
    function (chrome) {}
    ```
    当websocket连接建立后触发,chrome是Chome类型的实例。
    
    - disconnect
        
        ```
        function () {}
        ```
        关闭websocket连接时触发
        
    - error
    
        ```
        function (err) {}
        ```
    当通过host:port/json无法到达,或websocket连接无法建立时触发  
        err,Error类型的错误对象
        
  使用样例,针对chrome浏览器:
    
    ```
const Chrome = require('chrome-remote-interface');
Chrome(function (chrome) {
    with (chrome) {
        Network.requestWillBeSent(function (params) {
            console.log(params.request.url);
        });
        Page.loadEventFired(function () {
            close();
        });
        Network.enable();
        Page.enable();
        once('ready', function () {
            Page.navigate({'url': 'https://github.com'});
        });
    }
}).on('error', function (err) {
    console.error('Cannot connect to Chrome:', err);
});
    ```
        
2. module.Protocol([options],[callback])

    获取chrome调试协议描述符
    
    options object类型,具有如下属性:  
    - host 默认localhost
    - port 默认9222
    - remote 默认false
    
    callback 回调函数,在获取到协议内容后调用,函数接收如下参数:  
    - err Error一个错误对象,如果有错误的话
    - protocol 包含以下属性
        - remote 是否远程协议
        - descriptor chrome调试协议描述符
    
  使用样例:
    
    ```
const Chrome = require('chrome-remote-interface');
Chrome.Protocol(function (err, protocol) {
    if (!err) {
        console.log(JSON.stringify(protocol.descriptor, null, 4));
    }
});
    ```
    
3. module.List([options], [callback])

    获取所有的tabs,当然在node中只会有一个  
    
    options object类型,具有如下属性:  
    - host 默认localhost
    - port 默认9222
    - remote 默认false
    
    callback 回调函数,在获取到tabs内容后调用,函数接收如下参数:  
    - err Error一个错误对象,如果有错误的话
    - tabs 获取到的tab数组
    
  使用样例:
    
    ```
const Chrome = require('chrome-remote-interface');
Chrome.List(function (err, tabs) {
    if (!err) {
        console.log(tabs);
    }
});
    ```
    
4. module.New([options], [callback])

    创建新的tab
    
    options object类型,具有如下属性:  
    - host 默认localhost
    - port 默认9222
    - url 新tab加载的url 默认about:blank
    
    callback 回调函数,在新tab创建后调用,函数接收如下参数:  
    - err Error一个错误对象,如果有错误的话
    - tab 新增的tab
    
  使用样例:  
    
    ```
const Chrome = require('chrome-remote-interface');
Chrome.New(function (err, tab) {
    if (!err) {
        console.log(tab);
    }
});
  1. module.Activate([options], [callback])

    激活指定tab

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222
    • id 目标tab的id

    callback 回调函数,在新tab创建后调用,函数接收如下参数:

    • err Error一个错误对象,如果有错误的话

使用样例:

```

const Chrome = require('chrome-remote-interface');
Chrome.Activate({'id': 'CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC'}, function (err) {
if (!err) {
console.log('success! tab is closing');
}
});
```

  1. module.Close([options], [callback])

    关闭指定tab

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222
    • id 目标tab的id

    callback 回调函数,在新tab创建后调用,函数接收如下参数:

    • err Error一个错误对象,如果有错误的话

使用样例:

```

const Chrome = require('chrome-remote-interface');
Chrome.Close({'id': 'CC46FBFA-3BDA-493B-B2E4-2BE6EB0D97EC'}, function (err) {
if (!err) {
console.log('success! tab is closing');
}
});
```

  1. module.Version([options], [callback])

    获取版本信息

    options object类型,具有如下属性:

    • host 默认localhost
    • port 默认9222

    callback 回调函数,在新tab创建后调用,函数接收如下参数:

    • err Error一个错误对象,如果有错误的话
    • info json object

使用样例:

```

const Chrome = require('chrome-remote-interface');
Chrome.Version(function (err, info) {
if (!err) {
console.log(info);
}
});
```

  1. Chrome 类

    支持的事件:

    • event

      在远程调试目标发送通知时触发,一般是远程对象执行了客户端提交的方法后

      function (message) {}
      

      message包含如下属性:

      • method 通知内容,方法名 如:'Network.requestWillBeSent'
      • params 参数内容

    使用样例:

     ```
     chrome.on('event', function (message) {
         if (message.method === 'Network.requestWillBeSent') {
             console.log(message.params);
         }   
     });
     ```
    
    • 调试目标通过websocket发送了一个指定方法名的通知

      function (params) {}
      

      使用样例:

      chrome.on('Network.requestWillBeSent', console.log);
      
    • ready

      每次没有调试命令等待调试目标返回时触发

      function () {}
      

      使用样例:

      只在Network和Page激活后加载一个url

      chrome.Network.enable();
      chrome.Page.enable();
      chrome.once('ready', function () {
          chrome.Page.navigate({'url': 'https://github.com'});
      });
      

支持的方法
- chrome.send(method, [params], [callback])

    发送一个调试命令
    
    method 命令名称  
    params 参数  
    callback 当远程对象对该命令发送一个应答后调用,函数具有以下参数:  
    - error boolean 是否成功
    - response 如果error===true,返回一个error对象,{error:...},否则返回一个应答,{result:...}
    
    注意:在chrome调试规范里提到的id字段,在这里被内部管理不会暴露给用户
    
使用样例:
    
    ```
    chrome.send('Page.navigate', {'url': 'https://github.com'}, console.log);
    ```
    
- chrome..([params], [callback])
    
    是chrome.send('.', params, callback);的一种变形
    
    例如:  
    
    ```
    chrome.Page.navigate({'url': 'https://github.com'}, console.log);
    ```
- chrome..(callback)

    是chrome.on('.', callback)的变形
    
    例如:
    
    ```
    chrome.Network.requestWillBeSent(console.log);
    ```
- chrome.close([callback])

    关闭与远程调试目标的连接  
    callback会在websocket关闭成功后调用

你可能感兴趣的:(编程式调试node程序的利器chrome-remote-interface)