使用 vscode 调试 midwayjs 程序(包括源码)
# 使用 vscode 调试 midwayjs 程序(包括源码)
前言
- vscode 调试真的超级香(之前写的 ndb 调试可以让他吃灰了)
- 这次调试的不仅仅是node程序,还有能学习midwayjs源码
- 以下的内容操作思路来自 我是怎么调试 Nest 项目和源码的 (opens new window)@公众号-神光的编程秘籍,我是学了光哥的操作,转而学习调试midwayjs (如果你之前对vscode的debug完全没接触过可以先看光哥的视频,视频讲解的比较清晰。不过你要直接看文章也能看得懂~)
- 更多vscode调试技巧,推荐还是看光哥的 前端调试通关秘籍 (opens new window)。YYDS
- 在补充一句,midway这个node框架 (opens new window) 也很好用。值得尝试
来张调试的效果图
有几个值得关注的点
- 直接使用vscode调试启动的midaway项目
- 我打断点的地方是
@Get('/')
这是 midway 基于TS实现的一个标记 get 请求的装饰器 - 断点的时候,注意看控制台,这时候服务还没启动,程序就断点断住了
- 断点进去的时候,我是进入到了
node_modules\@midwayjs\decorator\src\web\requestMapping.ts
node_modules 的 TS 源码中(这个是重点要讲的) - 断点通过后,服务才启动了,监听了 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 install
, npm 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
}]
}
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}/**"
]
}
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
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条路可以选择
- 升级你的程序。 2.x 升级指南 (opens new window) 自己根据业务复杂度升级把。
我试用了一下官方提供的升级命令
npx --ignore-existing midway-upgrade
。问题不是特别大,对于 example 的那个程序来说升级后把configuration.ts
里面多出来的koaApplication
干掉就行。
升级后把新打包的代码覆盖过去就行(调试就可以看到我一开始的 gif 效果了)
(我只是调试个程序而已,还要升级框架,太夸张了、风险有点大)找到对应版本的源码包编译对应版本的 dist 代码。
想知道自己依赖包的版本可看midway文档: 查看当前包版本 (opens new window)
步骤如下:
- 用
npm ls 包名
查看包的版本 - 然后到 版本查询 (opens new window) 里面找到这个包发布的版本号
- 然后根据 git 记录下载源码
根据 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集成终端咋调
(如果你也有这习惯,那和我很像呢)
- 新增一个配置,选择node程序,
attach 模式
默认生成就是这样的配置
{
"name": "Attach",
"port": 9229,
"request": "attach",
"skipFiles": ["<node_internals>/**"],
"type": "node",
// 记得自己补上加载 sourcemap 的配置
"resolveSourceMapLocations": ["${workspaceFolder}/**"]
}
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 !