VSCode Debug技巧

Daotin 于 2025-03-11 发布 编辑
  1. 调试网页
    1. 配置详解
    2. 调试 Vue 项目
  2. 调试源码
    1. 调试 vue 源码
    2. 调试 vite 源码
    3. 调试 ElementUI 源码
    4. 断点是如何在网页里生效的
    5. 打断点的 7 种方式
  3. 调试 Node.js
    1. 使用vscode launch方式
    2. 使用vscode attach方式
    3. 使用 Chrome DevTools 调试 node 代码
    4. VSCode Node Debugger 配置
  4. 调试 npm scripts
  5. 调试移动端网页
  6. Charles工具使用
    1. 调试https请求
    2. Charles全功能简介
    3. 如何优雅的调试线上报错?

调试网页

配置详解

{
  "name": "vscode调试",

  // launch:launch 的意思是把 url 对应的网页跑起来,指定调试端口,然后页面会自动attach到这个端口。
  // attach:如果你已经有一个在调试模式跑的浏览器了,那直接 attach上就行
  "request": "launch",

  // 浏览器
  "type": "chrome",

  "runtimeArgs": [
    "--auto-open-devtools-for-tabs" // 打开网页都默认调起 Chrome DevTools
    "--incognito" // 无痕模式
  ],

  // "canary""stable""custom" 或浏览器可执行文件的路径。 Custom 表示自定义包装器、自定义生成或 CHROME_PATH 环境变量。
  "runtimeExecutable": "canary",

  // userDataDir 是保存用户数据的地方,比如你的浏览记录、cookies、插件、书签、网站的数据等等
  // 默认是 true,代表创建一个临时目录来保存用户数据。
  // 设置为false,可以记录登录状态、历史记录
  // 也可以指定一个自定义的路径,这样用户数据就会保存在那个目录下
  // 注意:userDataDir 只能跑一个 Chrome 实例,所以我使用chrome调试,edge用作其他搜索
  "userDataDir": false,

  "url": "<http://localhost:8080>",

  // workspaceFolder:  /  url 映射到了 ${workspaceFoder} 项目根目录
  "webRoot": "${workspaceFolder}",

  // 是否关闭sourcemap映射
  "sourceMaps": false,

  // 除了启动开发服务器然后连上 url 调试之外,也可以直接指定某个文件,VSCode Debugger 会启动静态服务器提供服务
  "file": "$workspaceFolder}/index.html"

  // sourcemap重映射:有时候,sourcemap 到的文件路径在本地里找不到,代码就是只读的,这时候就需要再次手动映射到本地文件
  // 以下是:默认有三个值,分别是把 meteor、webpack 开头的 path 映射到了本地的目录下。
  // 其中 ?:* 代表匹配任意字符,但不映射,而 * 是用于匹配字符并映射的。
  // 举例:最后一个 webpack://?:/  ${workspaceFolder}/* 的映射,就是把 webpack:// 开头,后面接任意字符 + / 然后是任意字符的路径映射到了本地的项目目录
  "sourceMapPathOverrides": {
    "meteor://💻app/*": "${workspaceFolder}/*",
    "webpack:///./~/*": "${workspaceFolder}/node_modules/*",
    "webpack://?:*/*": "${workspaceFolder}/*"
  }
}

常用配置:

{
  "name": "vscode调试",
  "request": "launch",
  "type": "chrome",
  "runtimeArgs": ["--auto-open-devtools-for-tabs"],
  "runtimeExecutable": "canary",
  "userDataDir": false,
  "url": "<http://localhost:8080>",
  "webRoot": "${workspaceFolder}"
}

调试 Vue 项目

启动后,先打个断点发现不起效,分析是路径不对。

怎么找路径?

先在代码里面写 debugger,进入调试窗口,查看目前的状况。

但问题就出现在后面多了一个 ?hash 的字符串,导致路径不对了。所以在我们 vue 代码里面打断点会显示未关联,因为对应的本地文件没有。

那为什么会多这样一个 hash 呢?

这是因为 vue cli 默认的 devtool 设置是 eval-cheap-module-source-map,sourceURL 的路径是通过 [module] 指定的,而模块名后默认会带 ?hash。

解决办法就是:从 eval-cheap-module-source-map 变为 source-map。

调试源码

调试 vue 源码

1、下载 vue 源码

git clone <https://github.com/vuejs/core> vue3-core

2、使用 pnpm 安装

PS:注意去掉 package.json 中的 puppeteer,用来做集成测试的,一是用不到,二是网络问题不去掉一直安装失败。

pnpm install

3、生成 sourcemap

pnpm add cross-env

然后去 packages 下各个包下的 dist 产物,你就会发现有 sourcemap 了。

4、把 runtime-core 包下的 dist 复制出来,替换 vue 项目的 @vue/runtime-core 下的 对应的 dist 目录。

注意是替换而不是删了整个 dist,因为还有一个文件是需要的。

image

注意 1:vue 源码的版本一定要和 vue 项目中使用的 vue 版本相同,否则启动会报错!

注意 2:使用 vite 搭建的 vue 项目没有生效。原因:vite 没有 source-map-loader 这些东西,无法读取 node_modules 下模块的 sourcemap。解决办法:一是调试源码就用 webpack 的 vue3 项目。二是把 vite 中配置 optimizeDeps: { exclude: ["vue"], } 排除一下 deps,然后删除 node_modules 下 .Vite文件夹。

注意 3:如果无法打断点,就把 vue 项目重新安装跑一下。。。

image

按照流程跑起来后,确实链接的是本地路径,不过现在 sourcemap 到的路径不大对,没有 runtime-core 的包名,不能编辑:

解决方式有 2 种:

  1. 一种是配置下 sourceMapPathOverrides,把这段路径再做一次映射,映射到源码目录就可以了。
  2. 另一种方式就是改造下 vue3 的 build 脚本,让生成的 sourcemap 就直接是正确的路径。

但是第一种的话不太好找,所以采用第二种。

// output.sourcemap = !!process.env.SOURCE_MAP
output.sourcemapPathTransform = (relativeSourcePath, sourcemapPath) => {
  const newSourcePath = path.join(
    path.dirname(sourcemapPath),
    relativeSourcePath
  );
  return newSourcePath;
};

重新 build 一下,然后进行 dist 复制。

注意:对于 webpack 的项目,这里还需要清除一下 babel loader 的缓存,删除 node_modules/.cache/babel-loader 即可。

调试 vite 源码

调试 ElementUI 源码

一、首先定位 ElementUI 源码

1、可以通过事件断点的方式,慢慢进入组件的源码。

2、当有了 sourcemap 之后,Chrome DevTools 会直接把 vue 文件列在 sources 里,我们可以找到对应的 vue 文件来打断点,就不用通过事件断点来找了。

能够调试 Element UI 源码之后,想知道组件内部都有哪些逻辑的话,就可以直接在源码断点调试了。

断点是如何在网页里生效的

比如源代码的路径是 /Users/xxx/vite-demo/src/App.vue ,最后打包后运行可能是http://xxx.com/bundle.js。

由于文件是关联了 sourcemap 的,所以就直接映射到了/Users/xxx/vite-demo/src/App.vue 文件,而 App.vue 中打的断点就是通过 CDP 调试协议进行通信的。

image

打断点的 7 种方式

image

image


调试 Node.js

使用vscode launch方式

1、添加一个 node 类型的 launch program 的调试配置,指定 program 的路径

2、你也想首行断住,可以加一个 stopOnEntry 的配置:

3、可以通过 args 来添加命令行参数:

使用vscode attach方式

1、以调试模式启动node

// --inspect 是以调试模式启动,--inspect-brk 是以调试模式启动并且在首行断住。
node --inspect-brk ./index.js

2、添加一个 node 类型的 attach 的调试配置,端口改成 ws 服务启动的端口 8888

3、然后点击 debug 启动

使用 Chrome DevTools 调试 node 代码

打开 chrome://inspect/#devices,下面列出的是所有可以调试的目标,也就是 ws 服务端:

你会发现这里列出了我们启动的跑的那个 node 脚本。点击 inspect 就可以调试这个 node 脚本了。

VSCode Node Debugger 配置

image

image

image

调试 npm scripts

这些命令行工具的 package.json 里都会有个 bin 字段,来声明有哪些命令,npm install 这个包以后,就会放到 node_modules/.bin 目录下。

这样我们就可以通过 node ./node_modules/.bin/xx 来跑不同的工具了。与使用 npm run xxx 一样。

1、在 .vscode/launch.json 的调试文件里,选择 node 的 launch program:用 node 执行 node_modules/.bin 下的文件,传入参数即可

image

2、VSCode Debugger 对 npm scripts 调试的场景做了封装,可以直接选择 npm 类型的调试配置,直接指定运行的命令即可

image

然后,我们就可以 node_modules/.bin 下这个文件里打个断点,或者想要查看默认webpack配置,可以在vue.config.js中打个断点进行调试。

默认调试模式下,输出的内容会在 Debug Console 面板显示:但这个也可以改:可以切换成 integratedTerminal,那就会输出在 terminal 了:

image

调试移动端网页

安卓调试:https://juejin.cn/book/7070324244772716556/section/7071922622262411296

IOS调试:ios 网页调试只能用 safari 浏览器,也就是你必须使用MacOS系统。

Charles工具使用

调试https请求

移动端怎么调试?

其实是一样的,只不过移动端也要把 Charles 证书安装到自己的系统中,需要点击安装 charles 证书到移动设备。

chrome 还有一个浏览器插件可以更细粒度的控制代理,叫做 SwitchyOmega。可以配置若干个代理服务器,比如 charles 的代理服务器。

要让你配置的规则生效,这里要选择 auto switch,也就是根据规则自动切换。

当你有多个代理服务器,或者想控制有的页面走代理有的不走的时候,就可以用这个插件来控制了。

Charles全功能简介

如何优雅的调试线上报错?

  1. 首先创建一个 vscode 调试配置,url对应线上地址
  2. 需要配置 “userDataDir”: “/users/daotin/mydatadir”, 到某个路径
  3. 勾选 uncaught exceptions,在未被捕获的异常处断住
  4. 然后启动调试,就会发现在未被捕获的异常处断住,但是发现代码是被压缩过的。
  5. 编译项目源码生成source-map(webpack 的 devtool 为 hidden-source-map,生成 sourcemap 但是不关联)
  6. 安装chrome插件 SwitchyOmega
  7. 配置proxy地址和端口(127.0.0.1:8888)
  8. 配置auto switch,让线上地址走proxy代理,之后点击应用选项
  9. 最后,代理方式设置成 auto switch
  10. charles设置断点:点击 Proxy > Breakpoint Settings,添加一个对线上地址的 xxx.js 响应的断点,强制刷下页面,charles 就会断住
  11. 然后可以修改响应的内容,加上了这样一行 sourcemap 的关联://# sourceMappingURL=http://www.guangtest.com:8084/dist/index.js.map
  12. 然后点击 execute 来执行修改,异常断点现在直接在源码处断住了。接下来就可以直接调试源码了,可以通过作用域、调用栈等信息来定位报错原因

参考:https://juejin.cn/book/7070324244772716556/section/7156796826728071200

注意:charles 断点修改的内容会缓存(比如添加的map文件),强制刷新(ctrl+shift+R)才会重新请求。