Nodejs 调试代码二

前文介绍了 Nodejs 调试代码的原理,本文讲解几个调试案例加深下理解,使用的是 Vscode 调试器客户端。

调试 Express 代码

初始化 express 工程。

$ mkdir express-demo
$ cd express-demo
$ npm init -y
$ npm install express

创建 index.js 文件,内容如下:

const express = require('express')
const app = express()

app.get('/', (req, res) => {
    const a = 1
    const b = 2
    const c = a + b
    res.end(`a + b = ${c}`)
})

app.listen('3000', function () {
    console.log('服务器已启动,端口', 3000)
})

方法一:request: launch

参考前文 Vscode 调试,添加配置文件如下:

// .vscode/launch.json
{
    "type": "node",
    "request": "launch",
    "name": "Express launch",
    "program": "${workspaceFolder}/index.js"
}

express 项目有个入口文件 index.js,平时启动服务需要输入 $ node index.js,调试的时候使用内置的调试器程序启动 index.js。

request: "launch" 表示使用调试器程序启动 index.js 文件。

方法二:request: attach

正常启动 Express 服务。

图1

此时突然想调试某个接口,如果使用 launch 方式,需要 Ctrl + C 停掉当前服务,然后用调试器程序重新执行 index.js。但是现在不想重启服务,又要对代码进行调试,可以使用 attach 方式。

添加调试配置文件如下。

// .vscode/launch.json
{
    "type": "node",
    "request": "attach",
    "name": "Express attach",
    "processId": "${command:PickProcess}",
    "port": 9229
}
  • request: "attach" 表示 Nodejs 程序已经在运行着,待会启动调试器程序,去关联这个已经运行的 Nodejs 程序;
  • processId: "${command:PickProcess}" 进程ID,后面花括弧里的东东不用管,意思当你点击 Vscode 调试面板绿色箭头(下图红字1)时会弹出一个下拉框让你选择:调试器程序关联哪一个正在运行的 Nodejs 程序(下图红字2)。
图2

我的机器上起了好几个 Nodejs 程序,跑 express-demo 的是第二个 Nodejs 程序,点击之后再看看终端,会打印一些新的消息,其中 Debugger attached 表示调试器程序已经和正在运行的 Nodejs 程序关联起来了。

图3

此时在 Vscode 中的源码里打个断点,在浏览器中访问 localhost:3000 可以看到进入断点了。

图4

调试 nodemon 代码

还是👆上面 Express 的例子,你会发现改动代码不会立即生效,需要重启服务才行。
第三方包 nodemon 可以监听文件变化,自动重启服务。(supervisor 包作用相同)

全局安装 nodemon:

$ npm install nodemon -g

修改 package.json 的 scripts 属性

"scripts": {
    "dev": "nodemon index.js"
}

此时执行 npm run dev 即可启动服务,修改 index.js 代码,会发现服务自动重启。

对于 Nodemon 启动的 Express 如何调试呢?

Vscode 打开调试配置,点击 Add Configuration(红字1),选择 Nodemon Setup(红字2)。

图5

Vscode 会自动生成一份调试配置文件。(program 属性默认入口文件为 app.js,这里改成我们的 index.js)

{
    "type": "node",
    "request": "launch",
    "name": "nodemon",
    "program": "${workspaceFolder}/index.js",
    "runtimeExecutable": "nodemon",
    "restart": true,
    "console": "integratedTerminal",
    "internalConsoleOptions": "neverOpen"
}

上面配置文件中前四个属性都有介绍过,这里主要介绍后四个属性的含义。

runtimeExecutable

使用哪个命令运行脚本,这里是 nodemon,启动调试器相当于执行 nodemon index.js。如果没有写 runtimeExecutable 这个属性,它的默认值为 "node"。

这里的 nodemon 需要全局安装,这样在环境变量 PATH 中才能找到该命令。

restart

加上这个配置,修改代码,调试器才会重启。

console

启动调试器后,会打印一些信息,如:调试器服务端监听哪个端口,调试器客户端是否连接上等。

console 配置有三个值,分别设置在什么地方打印这些信息:

  • integratedTerminal:Vscode 集成终端中打印信息,下图 Terminal 选项窗;
  • internalConsole:Vscode 里的调试控制台中打印信息,下图 Debug Console 选项窗;(改成这个吧~)
  • externalTerminal:打开系统自带的终端打印信息;
图6

internalConsoleOptions

internalConsole 即 Vscode 中的 Debug Console,在👆介绍 console 配置时已经介绍过了,internalConsoleOptions 设置是否自动打开 Debug Console 选项窗。

  • neverOpen:不会自动跳转到 Debug Console 选项窗,但是可以手动点击切换到 Debug Console 选项窗;
  • openOnSessionStart:即便当前在 Terminal 选项窗,当进行调试时,会自动跳转到 Debug Console 选项窗。
  • openOnFirstSessionStart:下同;

调试 Typescript 代码

上面👆Express 代码都是用原生 js 写的,如果用 Typescript 来写 Express 代码,如何调试呢?

调试之前,先要搭建 Typescript + Express 开发环境,参见 环境搭建

src 目录放 ts 写的代码;
dist 目录放编译后的 js 代码。

前面已经介绍过在 Vscode 中调试 js 代码,但是 ts 编译成的 js 代码丑陋无比,如下:

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var express_1 = __importDefault(require("express"));
var app = express_1.default();
app.get('/', function (req, res) {
    res.send('Hello Ts Express  dd ee ff');
});
app.listen(3000, function () {
    console.log('Server is running.');
});
//# sourceMappingURL=app.js.map

这导致我们想直接在 ts 文件上打断点,而非在 js 文件上打断点,如何做到这一点,是接下来的重点。

打开 Vscode 调试配置文件:

{
    "type": "node",
    "request": "launch",
    "name": "Launch Program",
    "program": "${workspaceFolder}/src/app.ts",
    "runtimeExecutable": "nodemon",
    "restart": true,
    "preLaunchTask": "tsc: build - tsconfig.json",
    "outFiles": ["${workspaceFolder}/dist/**/*.js"]
}

前面 6 个属性都介绍过,只有最后两个属性是陌生的。

preLaunchTask

在调试器启动入口文件之前执行这个任务,这里的任务是 tsc: build,即编译操作,将 src 目录下的 *.ts 文件编译成 *.js 文件;最终,调试器执行的还是 js 文件而非 ts 文件。

问题来了,调试器咋知道你编译后的 js 文件放在那里呢?下面👇属性 outFiles 告诉它的。

outFiles

该属性告诉调试器执行的 js 文件在哪个目录下,上面例子编译后的 js 文件都放在 dist 目录下。

既然调试器执行的是 js 代码,为什么我们可以在 ts 文件中打断点呢?

tsconfig.json 中有个配置项 sourceMap,当设置为 true 时,在 *.ts 文件编译成 *.js 文件时,会顺带生成 *.js.map 文件,这个文件将 *.ts 和 *.js 文件关联起来了,所以可以在 ts 文件打断点。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容