使用 vscode 调试 midwayjs 程序(包括源码)

10/2/2022 工具Node调试

# 使用 vscode 调试 midwayjs 程序(包括源码)

前言

  • vscode 调试真的超级香(之前写的 ndb 调试可以让他吃灰了)
  • 这次调试的不仅仅是node程序,还有能学习midwayjs源码
  • 以下的内容操作思路来自 我是怎么调试 Nest 项目和源码的 (opens new window)@公众号-神光的编程秘籍,我是学了光哥的操作,转而学习调试midwayjs (如果你之前对vscode的debug完全没接触过可以先看光哥的视频,视频讲解的比较清晰。不过你要直接看文章也能看得懂~)
  • 更多vscode调试技巧,推荐还是看光哥的 前端调试通关秘籍 (opens new window)。YYDS

来张调试的效果图

有几个值得关注的点

  1. 直接使用vscode调试启动的midaway项目
  2. 我打断点的地方是 @Get('/') 这是 midway 基于TS实现的一个标记 get 请求的装饰器
  3. 断点的时候,注意看控制台,这时候服务还没启动,程序就断点断住了
  4. 断点进去的时候,我是进入到了 node_modules\@midwayjs\decorator\src\web\requestMapping.ts node_modules 的 TS 源码中(这个是重点要讲的)
  5. 断点通过后,服务才启动了,监听了 3001 端口。这时候debug并没有结束(GIF太大了,后面的断点就不录了,比如在 controller某个步骤打个断点,然后请求一下接口也能进入调试状态)

# 调试准备

为了方便理解和你们能看到和我一致的效果,我直接clone了midaway 仓库最新代码 github - midway (opens new window)。如果你们想直接搞自己的项目也不是不行~

需要debug的程序就在仓库源码的 site/example/clss (opens new window) 中。这是一个简单的midway初始模版

然后安装个vscode和准备一台能运行ndoe的电脑(应该都有)

然后在 site/example/clss 运行 npm installnpm run dev 就能看到midway启动了一个node服务。

成功启动就可以进行下一步了

# 初步调试

先根据 midway文档中的调试部分 (opens new window) 运行下看看效果

  • 添加 .vscode/launch.json (port和protocol其实是多余的,贴进去编辑器就能看到是无效的,忽略这个问题)
{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [{
        "name": "Midway Local",
        "type": "node",
        "request": "launch",
        "cwd": "${workspaceRoot}",
        "runtimeExecutable": "npm",
        "windows": {
            "runtimeExecutable": "npm.cmd"
        },
        "runtimeArgs": [
            "run",
            "dev"
        ],
        "env": {
            "NODE_ENV": "local"
        },
        "console": "integratedTerminal",
        "protocol": "auto",
        "restart": true,
        "port": 7001,
        "autoAttachChildProcesses": true
    }]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

添加配置后直接启动调试的效果

  • 也是在 @Get 装饰器上打断点。程序也确实停住了
  • 进入调试目录会发现打开的其实是 requestMapping.js 。一个js文件(ts打包编译后的js)
  • 可以看到代码其实是编译后的,文件最下面 有一注释 sourceMappingURL=requestMapping.js.map。因为这个文件加载不到导致映射不到源码去,所以只能看到编译后的代码

打个广告: 关于sourcemap的更多解析和用法看光哥的 前端调试通关秘籍 (opens new window)

# 让debug加载 sourcemap 文件

问题一: vscode没有加载对应的 .map 文件

如果看了调试的视频你会发现有一个配置 resolveSourceMapLocations (默认配置文件也没写,需要自己加补上) 默认排除了 node_modules。

因为他的正则里面有个 !,所以调试的时候压根就没加载 node_modules 里面的 sourcemap ,调试的自然就不是源码。

所以直接把那一行删除

  • .vscode/launch.json
// vscode resolveSourceMapLocations 的默认配置
{
  // ... midway 推荐的配置
  
  "resolveSourceMapLocations": [
    "${workspaceFolder}/**",
    "!**/node_modules/**"
  ]
}

// 修改为
{
  // ... midway 推荐的配置
  
  "resolveSourceMapLocations": [
    "${workspaceFolder}/**"
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

问题2:npm包中压根也没有把.map文件传上去

咋办?看过视频的都知道,我们需要手动编源码,拿到 .map 文件,然后覆盖追加 .map 代码到 node_modules 对应的包中

midway 和 nextjs 编译不太一样,不过都是为了拿到 .map 文件就行。

# 编译 midway 源码与踩坑

# midway 源码编译

midway使用的是 lerna 进行多个功能包管理

我们调试的断点是 @Get 装饰器,他是属于 @midwayjs/decorator 包下的。 正常来说,我们只需要编译 packages/decorator (opens new window),拿到这个包的 .map 就完事了。 然而我对 lerna 认知有限,只能选择全部打包了

最一开始我们就说过 clone github - midway (opens new window)。我对 lerna 也不熟,我就直接说步骤了

# 在 clone 下来的 midway 代码根目录
npm install

# 使用 lerna 给子包安装依赖(我没全局装lerna,所以用 npx 启动)
npx lerna bootstrap

# 直接打包(这时候 lerna 会把所有的子包打包一次)
npm run build
1
2
3
4
5
6
7
8

打包后的代码在对应的 packages 模块下的 dist 目录。看截图的目录,这时候终于有 .map 文件了。

而且source 部分加载的路径是 ../../src 。所以等下 dist 目录下的 src 也要拷走

对比工具下可以看到 打包出来的文件(左) 和 我们要调试的程序对应的 node_modules 文件(右)。基本都是紫色的文件(说明是新增的文件)

新增的基本都是 .map 文件。还有 src 目录 ,test目录等...

如果这时候你也有对比工具,发现和我对比的结果不一样也不要惊讶!你的步骤没错 留心看我对比的文件夹其实是 midway-2.14.6。你们的目录应该是 midway,至于为什么后面踩坑会细说,所以放心大胆继续往下看

注意看还有2个红色的文件(红色代表有变更)

这2个文件可不能同步,可能有一些代码变更了获取其他原因,导致写法有些许差异,不过我亲测 这玩意影响运行

所以记得别同步。只同步 src 目录和新增的所有的 .map 文件就行

# 踩坑了!

我 clone 的是最新的 midway 代码(main分支 - 3.x版本)

而main分支中的 example 里面的代码依赖的是 2.x 版本 (听我说谢谢你)

如果跟着我的步骤,用 3.x 代码编译,和 example 的程序的 node_modules 包对比应该类似下面这样很多差异

这时候你有2条路可以选择

  1. 升级你的程序。 2.x 升级指南 (opens new window) 自己根据业务复杂度升级把。

我试用了一下官方提供的升级命令 npx --ignore-existing midway-upgrade 。问题不是特别大,对于 example 的那个程序来说升级后把 configuration.ts 里面多出来的 koaApplication 干掉就行。

升级后把新打包的代码覆盖过去就行(调试就可以看到我一开始的 gif 效果了)

  1. (我只是调试个程序而已,还要升级框架,太夸张了、风险有点大) 找到对应版本的源码包编译对应版本的 dist 代码。

想知道自己依赖包的版本可看midway文档: 查看当前包版本 (opens new window)

步骤如下:

根据 2.14.0 找到 versions/2_14_0-2_14_0.json (opens new window)。可以看到 "@midwayjs/decorator": "2.14.0" 证明没找错

我一开始直接找到 主版本 2.14.6 (opens new window) 去了,不过这 6个版本改动都不涉及 decorator,所以他的版本一直都是 2.14.0 不影响我们继续分析

确定版本号后,找到发布记录 releases/tag/v2.14.0 (opens new window)。直接下载这个源码包(如果你的git贼溜也可以通过 git切过去)

下载后,npm依赖,然后leran依赖,打包。和上面步骤一样,然后拷贝map文件和 src 目录 到要调试的程序中。

运行就是一开始的gif效果了,这时候断点就能直接进入到TS源码文件中

# 一些强迫症细节

# console 的输出位置

默认的 console 输出到了 debug console 的面板去了。而我们启动程序又是在 Terminal

通过修改配置,添加一条 "console": "externalTerminal" 就可以改回在终端输出了


# 习惯了用自己的终端,不喜欢用vscode集成终端咋调

(如果你也有这习惯,那和我很像呢)

  1. 新增一个配置,选择node程序,attach 模式

默认生成就是这样的配置

{
  "name": "Attach",
  "port": 9229,
  "request": "attach",
  "skipFiles": ["<node_internals>/**"],
  "type": "node",
  // 记得自己补上加载 sourcemap 的配置
  "resolveSourceMapLocations": ["${workspaceFolder}/**"]
}
1
2
3
4
5
6
7
8
9

这时候就不用管 console 配置了,因为都已经在你的终端运行,vscode只是连接上对应的调试协议而已

问题来了: vscode 如何连接上外部终端启动的程序?

node --inspect 命令(网上介绍很多了,调试秘籍也有教,我就不细说了)

看到启动了一个 websocket,重点在他的端口号 9229 ,和vscode调试配置中的 "port": 9229 能对上就行,默认都是 9229

也能指定端口号运行 node --inspect=9999

这时候 vscode 的 port 就改为 9999 就可以连上(方便启动多个项目调试)


回到 midway ,虽然用的 npm run dev 方式启动,不过文档也有提供自行启动调试的方法 在-chrome-中调试 (opens new window)。只要添加 --debug 启动参数即可

所以把 package.json dev 启动命令改一下 "dev": "cross-env NODE_ENV=local midway-bin dev --ts --debug"

可以看到启动命令变了,也输出了调试地址,可以看到端口号是 9229


midway 也能指定debug的端口,而且并不会影响程序启动的端口(只要别写同一个)

接下来就是外部终端先启动 midway 服务。

然后 vscode启动调试(启动模式别选错了,因为我们现在已经有2份配置)

最后效果如下:

正常情况下如果没启动debug,断点也不会生效,当启动debug后 ,在刷新断点就生效了。这种用来调试自己的业务就很香~

需要注意的是,我打了个断点,这时候 @Get 断点是没进去的
因为那是服务启动前程序初始化才执行的(所以用外部终端的话很难观察到这部分源码执行)
想看源码 debug 还得老老实实用配套的终端

# 最后

现在的工具真是越来越好用。

当然也少不了发明这些工具的人,尝试使用这些工具,总结踩坑经验的大佬

前端调试通关秘籍 (opens new window)midway (opens new window) YYDS !

Last Updated: 1/7/2024, 5:51:59 PM