編程式調(diào)試node程序的利器chrome-remote-interface

簡介

chrome-remote-interface是chrome調(diào)試協(xié)議的第三方調(diào)試客戶端實(shí)現(xiàn),該項(xiàng)目開源,提供了命令行工具,且為node程序提供了api。
chrome-remote-interface為基于chrome調(diào)試協(xié)議編寫自己的node調(diào)試工具提供了便捷的途徑,因?yàn)槔盟?,你不需要基于原始的協(xié)議通過websocket編程去開發(fā)調(diào)試工具了。
項(xiàng)目地址https://github.com/cyrus-and/chrome-remote-interface。

使用命令行

安裝

通過npm進(jìn)行安裝

npm install chrome-remote-interface

啟動(dòng)調(diào)試目標(biāo)

chrome-remote-interface基于chrome調(diào)試協(xié)議,因此其支持調(diào)試chrome瀏覽器和node運(yùn)行環(huán)境。
無論哪種調(diào)試目標(biāo),其啟動(dòng)時(shí)都應(yīng)該指定調(diào)試端口。
如果要調(diào)試chrome瀏覽器,應(yīng)該在啟動(dòng)chrome時(shí)添加--remote-debugging-port參數(shù),如下:

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

如果調(diào)試node,在啟動(dòng)時(shí)添加--inspect參數(shù),如下:

node --inspect=9222 app.js

此時(shí),node會(huì)輸出:

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

題外話:如果只是希望調(diào)試node,并不打算開發(fā)一個(gè)調(diào)試node的工具的話,根據(jù)提示中的url,在chrome中打開就直接可以用chrome的開發(fā)工具調(diào)試了。

體驗(yàn)命令行

  • 查看全部命令

    在終端輸入chrome-remote-interface并回車,可看到如下輸出:

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

Commands:

inspect [options] [<target>] inspect a target (defaults to the current tab)
list                   list all the available tabs
new [<url>]            create a new tab
activate <id>          activate a tab by id
close <id>             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 <host>  HTTP frontend host
-p, --port <port>  HTTP frontend port
```

其中,new和close是針對(duì)瀏覽器的tab的命令,不要針對(duì)node來運(yùn)行。
  • 查看所有頁面實(shí)例

    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的開發(fā)工具,可以直接用該工具調(diào)試。和啟動(dòng)node時(shí),node提示的url是一個(gè)用途。
    id是當(dāng)前頁面標(biāo)識(shí)。
    url是當(dāng)前頁面url。
    webSocketDebuggerUrl是node提供的ws協(xié)議的調(diào)試服務(wù),調(diào)試客戶端需要通過該url連接到調(diào)試服務(wù)。

  • 查看調(diào)試目標(biāo)版本

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

    輸出:

    [ { Browser: 'node.js/v7.0.0', 'Protocol-Version': '1.1' } ]
    
  • 查看調(diào)試目標(biāo)支持的調(diào)試協(xié)議

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

    輸出:

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

    remote:false說明協(xié)議內(nèi)容是工具自帶的協(xié)議文件,并不是來自調(diào)試目標(biāo)。
    如果要獲取調(diào)試目標(biāo)的協(xié)議內(nèi)容要添加-r選項(xiàng),如:

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

    輸出:

    { 
    remote: true,
    descriptor: {
        { version: { major: '1', minor: '1' },
        domains:[略]
    }
    }
    
  • 調(diào)試命令

    chrome-remote-interface -t 127.0.0.1 -p 9222 inspect -r
    -r 表示應(yīng)用調(diào)試目標(biāo)提供的協(xié)議描述文件
    通過inspect可以調(diào)試node或chrome所支持的各個(gè)域。

    Console域體驗(yàn)

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

Debugger域體驗(yàn)

```

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

HeapProfiler域體驗(yàn)

```

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

Profiler域體驗(yàn)

```

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域體驗(yàn)  
>>> Runtime.evaluate({expression:"1+1"})
{ result: { result: { type: 'number', value: 2, description: '2' } } }

Schema域體驗(yàn)

>>> 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' } ] } }
    ```
    
    體驗(yàn)事件處理
    
    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調(diào)試協(xié)議連接調(diào)試目標(biāo)
    
    options object類型,具有如下屬性:  
    - host 默認(rèn)localhost
    - port 默認(rèn)9222
    - chooseTab 決定調(diào)試哪個(gè)tab。該參數(shù)可以為三種類型:
        - function 提供一個(gè)返回tab序號(hào)的函數(shù)
        - object 正如new 和 list返回的對(duì)象一樣
        - string websocket url
        默認(rèn)為一個(gè)函數(shù),返回當(dāng)前激活狀態(tài)的tab的序號(hào),如:function(tabs){return 0;}
    - protocol 協(xié)議描述符,默認(rèn)由remote選項(xiàng)來定是否使用調(diào)試目標(biāo)提供的協(xié)議描述符
    - remote 默認(rèn)false,如果protocol設(shè)置了,該選項(xiàng)不會(huì)起作用
    
  callback   
    如果callback是函數(shù)類型,則該函數(shù)在connect事件發(fā)生后會(huì)得到回調(diào),并返回EventEmitter對(duì)象,如果不是,則返回Promise對(duì)象。
    
    EventEmitter對(duì)象支持如下事件:  
    
    - connect
    
        ```
    function (chrome) {}
    ```
    當(dāng)websocket連接建立后觸發(fā),chrome是Chome類型的實(shí)例。
    
    - disconnect
        
        ```
        function () {}
        ```
        關(guān)閉websocket連接時(shí)觸發(fā)
        
    - error
    
        ```
        function (err) {}
        ```
    當(dāng)通過host:port/json無法到達(dá),或websocket連接無法建立時(shí)觸發(fā)  
        err,Error類型的錯(cuò)誤對(duì)象
        
  使用樣例,針對(duì)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調(diào)試協(xié)議描述符
    
    options object類型,具有如下屬性:  
    - host 默認(rèn)localhost
    - port 默認(rèn)9222
    - remote 默認(rèn)false
    
    callback 回調(diào)函數(shù),在獲取到協(xié)議內(nèi)容后調(diào)用,函數(shù)接收如下參數(shù):  
    - err Error一個(gè)錯(cuò)誤對(duì)象,如果有錯(cuò)誤的話
    - protocol 包含以下屬性
        - remote 是否遠(yuǎn)程協(xié)議
        - descriptor chrome調(diào)試協(xié)議描述符
    
  使用樣例:
    
    ```
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,當(dāng)然在node中只會(huì)有一個(gè)  
    
    options object類型,具有如下屬性:  
    - host 默認(rèn)localhost
    - port 默認(rèn)9222
    - remote 默認(rèn)false
    
    callback 回調(diào)函數(shù),在獲取到tabs內(nèi)容后調(diào)用,函數(shù)接收如下參數(shù):  
    - err Error一個(gè)錯(cuò)誤對(duì)象,如果有錯(cuò)誤的話
    - tabs 獲取到的tab數(shù)組
    
  使用樣例:
    
    ```
const Chrome = require('chrome-remote-interface');
Chrome.List(function (err, tabs) {
    if (!err) {
        console.log(tabs);
    }
});
    ```
    
4. module.New([options], [callback])

    創(chuàng)建新的tab
    
    options object類型,具有如下屬性:  
    - host 默認(rèn)localhost
    - port 默認(rèn)9222
    - url 新tab加載的url 默認(rèn)about:blank
    
    callback 回調(diào)函數(shù),在新tab創(chuàng)建后調(diào)用,函數(shù)接收如下參數(shù):  
    - err Error一個(gè)錯(cuò)誤對(duì)象,如果有錯(cuò)誤的話
    - 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 默認(rèn)localhost
    • port 默認(rèn)9222
    • id 目標(biāo)tab的id

    callback 回調(diào)函數(shù),在新tab創(chuàng)建后調(diào)用,函數(shù)接收如下參數(shù):

    • err Error一個(gè)錯(cuò)誤對(duì)象,如果有錯(cuò)誤的話

使用樣例:

```

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])

    關(guān)閉指定tab

    options object類型,具有如下屬性:

    • host 默認(rèn)localhost
    • port 默認(rèn)9222
    • id 目標(biāo)tab的id

    callback 回調(diào)函數(shù),在新tab創(chuàng)建后調(diào)用,函數(shù)接收如下參數(shù):

    • err Error一個(gè)錯(cuò)誤對(duì)象,如果有錯(cuò)誤的話

使用樣例:

```

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 默認(rèn)localhost
    • port 默認(rèn)9222

    callback 回調(diào)函數(shù),在新tab創(chuàng)建后調(diào)用,函數(shù)接收如下參數(shù):

    • err Error一個(gè)錯(cuò)誤對(duì)象,如果有錯(cuò)誤的話
    • info json object

使用樣例:

```

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

  1. Chrome 類

    支持的事件:

    • event

      在遠(yuǎn)程調(diào)試目標(biāo)發(fā)送通知時(shí)觸發(fā),一般是遠(yuǎn)程對(duì)象執(zhí)行了客戶端提交的方法后

      function (message) {}
      

      message包含如下屬性:

      • method 通知內(nèi)容,方法名 如:'Network.requestWillBeSent'
      • params 參數(shù)內(nèi)容

    使用樣例:

     ```
     chrome.on('event', function (message) {
         if (message.method === 'Network.requestWillBeSent') {
             console.log(message.params);
         }   
     });
     ```
    
    • <method>

      調(diào)試目標(biāo)通過websocket發(fā)送了一個(gè)指定方法名的通知

      function (params) {}
      

      使用樣例:

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

      每次沒有調(diào)試命令等待調(diào)試目標(biāo)返回時(shí)觸發(fā)

      function () {}
      

      使用樣例:

      只在Network和Page激活后加載一個(gè)url

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

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

    發(fā)送一個(gè)調(diào)試命令
    
    method 命令名稱  
    params 參數(shù)  
    callback 當(dāng)遠(yuǎn)程對(duì)象對(duì)該命令發(fā)送一個(gè)應(yīng)答后調(diào)用,函數(shù)具有以下參數(shù):  
    - error boolean 是否成功
    - response 如果error===true,返回一個(gè)error對(duì)象,{error:...},否則返回一個(gè)應(yīng)答,{result:...}
    
    注意:在chrome調(diào)試規(guī)范里提到的id字段,在這里被內(nèi)部管理不會(huì)暴露給用戶
    
使用樣例:
    
    ```
    chrome.send('Page.navigate', {'url': 'https://github.com'}, console.log);
    ```
    
- chrome.<domain>.<method>([params], [callback])
    
    是chrome.send('<domain>.<method>', params, callback);的一種變形
    
    例如:  
    
    ```
    chrome.Page.navigate({'url': 'https://github.com'}, console.log);
    ```
- chrome.<domain>.<event>(callback)

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

    關(guān)閉與遠(yuǎn)程調(diào)試目標(biāo)的連接  
    callback會(huì)在websocket關(guān)閉成功后調(diào)用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容