In‑Depth Guide to Node.js Inspector: Usage, Principles, and Implementation
This article provides a comprehensive tutorial on using Node.js Inspector for local and remote debugging, automatic detection, data collection (heap snapshots and CPU profiles), dynamic activation, and a detailed walkthrough of its internal architecture and communication flow between the client, WebSocket, and V8 Inspector.
1. Using Node.js Inspector
Node.js ships with a powerful Inspector that can debug code, collect heap snapshots, CPU profiles, and other runtime data. It can be started locally with node --inspect or remotely by exposing a WebSocket endpoint.
1.1 Local Debugging
Example of a simple HTTP server:
const http = require('http');
http.createServer((req, res) => {
res.end('ok');
}).listen(80);Run it with node --inspect httpServer.js and open Chrome DevTools to see the Node.js debugging button.
1.2 Remote Debugging
Start the server on a remote host: node --inspect=0.0.0.0:8888 httpServer.js Connect from the browser using a URL like:
devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=1.1.1.1:8888/abcd12341.3 Automatic Detection
Chrome can auto‑detect Node.js processes via chrome://inspect/#devices, then click configure and add the remote address.
1.4 Data Collection
Use the V8 Inspector to collect HeapSnapshot and CPU Profile data. The following code opens a session and writes a CPU profile to a file:
const inspector = require('inspector');
const http = require('http');
const fs = require('fs');
function getCpuprofile(req, res) {
const session = new inspector.Session();
session.connect();
session.post('Profiler.enable', () => {
session.post('Profiler.start', () => {
setTimeout(() => {
session.post('Profiler.stop', (err, {profile}) => {
if (!err) fs.writeFileSync('./profile.cpuprofile', JSON.stringify(profile));
session.disconnect();
res.end('ok');
});
}, 3000);
});
});
}
http.createServer((req, res) => {
if (req.url == '/debug/getCpuprofile') getCpuprofile(req, res);
else res.end('ok');
}).listen(80);1.5 Dynamic Enabling
Because the default inspector is unsafe, you can enable it on demand:
const inspector = require('inspector');
const http = require('http');
let isOpened = false;
function getHTML() {
return `<html><meta charset="utf-8"/><body>Copy this URL to a new Tab to start debugging devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=${inspector.url().replace("ws://", "")}</body></html>`;
}
http.createServer((req, res) => {
if (req.url == '/debug/open') {
if (!isOpened) { isOpened = true; inspector.open(); }
res.end(getHTML());
} else if (req.url == '/debug/close') {
if (isOpened) { inspector.close(); isOpened = false; }
res.end('ok');
} else {
res.end('ok');
}
}).listen(80);2. Inspector Debugging Principle
When a browser connects, it establishes a WebSocket connection and exchanges JSON‑RPC messages defined by the Inspector protocol. Commands such as Debugger.scriptParsed and Debugger.setBreakpointByUrl are used to set breakpoints and retrieve script sources.
3. Implementation Details of Node.js Inspector
3.1 Initialization
Node creates an inspector::Agent and starts an I/O thread:
inspector_agent_ = std::make_unique<inspector::Agent>(this);
inspector_agent_->Start(...);
inspector_agent_->StartIoThread();3.2 Connection Handling
A Libuv TCP server listens on a port, accepts connections, and upgrades HTTP to WebSocket. The flow is:
Accept TCP socket → ServerSocket::Accept Create SocketSession and InspectorSocket Parse HTTP request, send 101 Switching Protocols Switch handler to
WsHandler3.3 Protocol Upgrade
After the upgrade, the server sends a 101 response and replaces the protocol handler:
inspector->SwitchProtocol(new WsHandler(inspector, std::move(tcp)));3.4 Data Flow from Client to V8
WebSocket frames are decoded, then forwarded through SocketSession::Delegate::OnWsFrame → InspectorSocketServer::MessageReceived → InspectorIoDelegate::MessageReceived → CrossThreadInspectorSession::Dispatch → V8 ChannelImpl which finally calls session_->dispatchProtocolMessage.
3.5 Data Flow from V8 to Client
V8 sends a response via ChannelImpl::sendResponse, which goes through IoSessionDelegate, enqueues a TransportAction::kSendMessage, and is written back to the WebSocket by WsHandler::Write → TcpHolder::WriteRaw → Libuv uv_write.
4. Summary
Node.js Inspector provides a powerful way to debug, profile, and collect runtime data from Node.js processes, supporting both local and remote scenarios, dynamic activation, and a well‑structured internal architecture that bridges the client, WebSocket, and V8 Inspector.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ByteDance Web Infra
ByteDance Web Infra team, focused on delivering excellent technical solutions, building an open tech ecosystem, and advancing front-end technology within the company and the industry | The best way to predict the future is to create it
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
