zen·工作环境搭建之调试篇

一般浏览器或者微信开发工具都能调试,现网的话代码混淆过需要sourcemap映射源代码。这里主要说的是Node的调试。众所周知Node提供了调试的方法open in new window
简单说一下有这么几种

node调试open in new window

node inspect命令使用方式如下

简单说下就是node的debug模式有client跟server两部分,server运行代码并接收client的命令调整运行姿势。client可以是多种方式,如Chrome,VSCode,node默认的命令行CLI debugger

node inspect

如下命令行直接进入命令行调试模式,可以通过按键进行调试等。本质是启动一个独立于node进程的调试程序

node inspect main.js # 等价于 node debug main.js



如上图,创建了两个进程pid分别为44335和44334

  • 44334主进程用于运行CLI debugger调试器
  • 44335子进程用于node进入--inspect监视模式跑用户的脚本。

一句话总结就是node inspect 包含 node --inspect-brk

node inspect这种CLI的方式比较low,没图形化界面,断点要执行命令,不适合大项目使用

node --inspect与client结合调试

TIP

node --inspectnode --inspect-brk很像,区别在于node --inspect-brk会进入首行断点模式,而node --inspect则是遇到debugger或者断点才会停止

原理:V8 检查器的集成允许将 Chrome 开发者工具附加到 Node.js 实例,以便进行调试和性能分析。 它使用了 Chrome 开发者工具协议open in new window。当node进程有--inspect参数的时候进入监听模式,会监听client的指令,默认node监听127.0.0.1:9229,同时有一个UUID随机数防止串听

注意下这里默认的监听IP是127.0.0.1本地,外部连过来的话IP要起到0.0.0.0才行

node文档这里说的很明显open in new window,默认127.0.0.1:9229是为了保证安全。因为调试其实是可以执行任意代码的。127.0.0.1默认作为回环地址,用于调试。

可在/etc/hosts文件中与localhost绑定,如下

[root@VM-91-2-centos /etc]# cat /etc/hosts
127.0.0.1 VM-91-2-centos VM-91-2-centos
127.0.0.1 localhost.localdomain localhost
127.0.0.1 localhost4.localdomain4 localhost4

::1 VM-91-2-centos VM-91-2-centos
::1 localhost.localdomain localhost
::1 localhost6.localdomain6 localhost6
node --inspect main.js

image-20210514161312823
运行引用,浏览器键入chrome://inspect/#devices与进程链接,调试工具默认通信端口为9229,ip默认为127.0.0.1(本地用)

-e参数支持传入代码eval执行,如node --inspect=9229 -e "setTimeout(function() { console.log('yes'); }, 30000)"

node --inspect-brk 首行断点

node --inspect-brk=9229 app.js
node --inspect-brk app.js

process._debugProcess

如果一个 Node.js 进程已经启动,没有添加 --inspect 参数,我不想重启又想调试怎么办?幸好我们有 process._debugProcess。

  1. 通过 ps 命令查看当前启动的 Node.js 进程的 pid,如:53911
  2. 打开新的终端,运行:node -e "process._debugProcess(53911)",原来的 Node.js 进程会打印出:Debugger listening on ws://127.0.0.1:9229/2331fa07-32af-45eb-a1a8-bead7a0ab905
  3. 使用client链接debug server调试,如 NIM 调出 Chrome DevTools 进行调试

子进程调试

默认调试只能调试主进程,如果是多进程部署的话,子进程不能调试,可以用ndbopen in new window

也可以参考这里open in new window的做法

一般遇到子进程调试就是生产环境的模式了,我们生产环境是pm2多进程部署的,遇到pm2调试多进程的坑,大概如下

  1. fork模式,单实例(instance)可以运行
  2. fork模式,多实例,只能运行1个进程,其他报错
  3. cluster模式,单实例(instance)不可以运行
  4. cluster模式,多实例(instance)不可以运行

其次是调试看着是基于WS的,但是测试直接WS转发不行,能搜索到但是连接Chrome devtools没内容。
最后只能根据Node文档说的走SSH端口转发,但是SSH端口转发风险也很大,就是能到端口的都能到生产环境Node去执行,最后被运维ban了-_-!!

Chrome浏览器插件NIMopen in new window

NIMopen in new window这个插件可以自动发现本地开启的debug server,并自动打开Chrome的调试页面

VSCode调试

VSCode其实相当于client,发出命令给已经启动的debug server。同时VSCode又能另起debug server,配置好了直接一键启动debug server后attach上去。这里VSCode单独一篇是因为一些配置说明和确实符合实际使用,因此单独成章详细说明。VSCode已经内置了debug不需要安装插件,其他语言可能需要安装插件支持调试。

VSCode Debuggingopen in new window

一个简单的例子

const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();

const a = 1
const b = 2
const main = (ctx, next) => {
  console.log(a+b)
  console.log(`main exec`)
  ctx.response.body = 'ManfredHu Hello World';
};

const welcome = (ctx, next) => {
  console.log(`welcome exec`, ctx.params)
  ctx.response.body = `Hello ${ctx.params}`;
};

const mainRouter = new Router()
mainRouter.get('/', main)
mainRouter.get('/:name', welcome)

// app.use(router.get('/', main));
// app.use(router.get('/:name', welcome));
app.use(mainRouter.routes());
app.use(mainRouter.allowedMethods());
app.listen(3000, '0.0.0.0');
console.log('listening on port 3000');

简单起个demo,运行koa监听端口3000

VSCode debug开关选项

  • smart (default) - 如果在node_modules外执行代码则进程会进入debug模式,可以通过配置正则定义这里的范围,见setting (debug.javascript.autoAttachSmartPattern)
  • always - 所有的node都会进入debug模式
  • onlyWithFlag - 只有--inspect or --inspect-brk标识的会进入debug模式

Auto Attach

简单理解就是不用管debug,VSCode会自动检测需要作为debug client去attach debug server。

这里VSCode有开关,可以搜索auto attch开关来切换各个模式,CMD+Shift+P输入auto attach
CMD+Shift+P输入auto attach
auto attach选项

选择好后重启终端再执行命令就可以了,如上图我打在请求进来的时候,浏览器访问http://0.0.0.0:3000/open in new window就停在那里了

可以看到这里ctx变量里header有host、user-agent等值

视频可以看这里open in new window

JavaScript Debug Terminal

很少用,不过也有

launch.json配置

Auto Attach比较智能,但是只有自己用,怎么给项目内其他人一起用呢?用配置文件,简单.vscode/launch.json配置如下,更复杂的看launch-configuration-attributesopen in new window

{
  // 使用 IntelliSense 了解相关属性。 
  // 悬停以查看现有属性的描述。
  // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "skipFiles": [
        "<node_internals>/**"
      ],
      "program": "${workspaceFolder}/app.js"
    }
  ]
}

ts-node调试cli

js的server调试估计看完上面的都会了,但是ts-node的cli调试不知道大家会不会。这里介绍一下

ts-node是一个可以直接运行ts代码的node工具,可以看下npm文档open in new window

基本可以认为ts-node就是ts版本的node执行工具了,毕竟node默认只支持js而不支持ts。ts要跑node的话要先tsc编译一遍,调试的时候就比较麻烦了。

# Execute a script as `node` + `tsc`.
ts-node script.ts

# Starts a TypeScript REPL.
ts-node

# Execute code with TypeScript.
ts-node -e 'console.log("Hello, world!")'

# Execute, and print, code with TypeScript.
ts-node -p -e '"Hello, world!"'

# Pipe scripts to execute with TypeScript.
echo 'console.log("Hello, world!")' | ts-node

# Equivalent to ts-node --transpile-only
ts-node-transpile-only script.ts

# Equivalent to ts-node --cwd-mode
ts-node-cwd script.ts

所以这里用ts-node代替node执行,然后cli因为不是在项目本身目录执行的,要做一些修改。我们要的效果是可以直接运行ts代码不需编译,这个称为debug模式

文件目录大致如下

  • index.ts
  • debug.js
  • package.json
  • src
    • index.ts
package.json内容
{
  "bin": {
    "xxx": "./dist/index.js",
    "xxx-debug": "debug.js"
  }
}
src/debug.js内容
#!/usr/bin/env node

// picture-debug to enter debug mode
// will output debug info
const tsConfigPath = require('path').resolve(__dirname, "./tsconfig.json")
const config = require(tsConfigPath);
require("ts-node").register(config);
require("./index.ts");
index.ts内容
#!/usr/bin/env node

import index from './src/index'
index()

这时npm link后执行xxx-debug就直接跑ts代码了。

VSCode+ts-node调试cli

上面可以直接执行ts代码,在调试的时候其实还不够,我想要配合VSCode做断点调试,设置VSCode的launch配合调试就可以了,此处配置来源于这里open in new window

.vscode/launch.json内容
{
  // 使用 IntelliSense 了解相关属性。 
  // 悬停以查看现有属性的描述。
  // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch index.ts",
      "type": "node",
      "request": "launch",
      "runtimeArgs": [
        "-r",
        "ts-node/register"
      ],
      "args": [
        "${workspaceFolder}/src/index.ts",
      ],
      "skipFiles": [
        "node_modules/**"
      ]
    }
  ]   
}

也可以看这里手把手教学:使用 TypeScript 开发 Node.js 应用open in new window

Last Updated:
<manfred>峯</hu>
欢迎关注微信公众号 【Big前端】无广告,无软文,就是这么傲娇。直推一线大厂高质量内容,不局限于前端·后台·运维相关,还包括房价🏠、信用卡💳等内容也可内推一线大厂腾讯阿里字节,对腾讯字节比较熟悉,简历可以发给我,我会给你介绍一线大厂的情况,让你更加了解一线大厂