VSCode Debugger 调试网页
VSCode Debugger 的配置
{
"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
,进入调试窗口,查看目前的状况。
- 发现他从一个乱七八糟的路径,映射到了 webpack://vue-demo1/src/App.vue?11c4 的路径下。
- 然后在 VSCode Debugger 里看看这个路径,发现是 /Users/guang/code/vue-demo1/src/App.vue?11c4
- 其实这个路径已经做过了映射,就是完成了从 webpack:///vue-demo1/src/App.vue?11c4 到 /Users/guang/code/vue-demo1/src/App.vue?11c4 的映射。(使用的 sourceMapPathOverrides 的第三条配置)
但问题就出现在后面多了一个 ?hash 的字符串,导致路径不对了。所以在我们 vue 代码里面打断点会显示未关联,因为对应的本地文件没有。
那为什么会多这样一个 hash 呢?
这是因为 vue cli 默认的 devtool 设置是 eval-cheap-module-source-map
,sourceURL 的路径是通过 [module] 指定的,而模块名后默认会带 ?hash。
解决办法就是:从 eval-cheap-module-source-map 变为 source-map。
- 去掉 module(最后 webpack 的配置为:
config.devtool = "source-map"
) - 添加配置(具体可以打断点在调试界面看路径)
"sourceMapPathOverrides": { "webpack:///src/*": "${workspaceFolder}/src/*" }
调试源码
调试 vue 源码
1、下载 vue 源码
git clone https://github.com/vuejs/core vue3-core
2、使用 pnpm 安装
PS:注意去掉 package.json 中的
puppeteer
,用来做集成测试的,一是用不到,二是网络问题不去掉一直安装失败。
pnpm install
3、生成 sourcemap
- 方式一:直接
pnpm run build --sourcemap
打包即可 - 方式二:由于在 rollup.config.js 看到
output.sourcemap = !!process.env.SOURCE_MAP
,想要生成 sourcemap,需要 SOURCE_MAP 环境变量为 true。 - 安装 cross-env
pnpm add cross-env
- 设置
"build": "cross-env SOURCE_MAP=true node scripts/build.js"
- 使用
pnpm run build
打包
然后去 packages 下各个包下的 dist 产物,你就会发现有 sourcemap 了。
4、把 runtime-core
包下的 dist 复制出来,替换 vue 项目的 @vue/runtime-core
下的 对应的 dist 目录。
注意是替换而不是删了整个 dist,因为还有一个文件是需要的。
注意 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 项目重新安装跑一下。。。
按照流程跑起来后,确实链接的是本地路径,不过现在 sourcemap 到的路径不大对,没有 runtime-core 的包名,不能编辑:
解决方式有 2 种:
- 一种是配置下 sourceMapPathOverrides,把这段路径再做一次映射,映射到源码目录就可以了。
- 另一种方式就是改造下 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 源码
TODO
调试 ElementUI 源码
一、首先定位 ElementUI 源码
1、可以通过事件断点的方式,慢慢进入组件的源码。
- 但是组件的代码是被编译打包过的,不是最初的源码。
- 为了调试最初的源码,需要下载了 Element UI 的代码,build 出了一份带有 sourcemap 的代码。覆盖项目 node_modules 下的代码,重新跑 dev server,这时候就可以直接调试组件源码了。
2、当有了 sourcemap 之后,Chrome DevTools 会直接把 vue 文件列在 sources 里,我们可以找到对应的 vue 文件来打断点,就不用通过事件断点来找了。
能够调试 Element UI 源码之后,想知道组件内部都有哪些逻辑的话,就可以直接在源码断点调试了。
VSCode Debugger 打的断点是如何在网页里生效的
比如源代码的路径是 /Users/xxx/vite-demo/src/App.vue ,最后打包后运行可能是http://xxx.com/bundle.js。
由于文件是关联了 sourcemap 的,所以就直接映射到了/Users/xxx/vite-demo/src/App.vue 文件,而 App.vue 中打的断点就是通过 CDP 调试协议进行通信的。
打断点的 7 种方式
- 异常断点(Uncaught Exceptions):在抛异常处断住
- 条件断点(conditional breakpoint):在满足某个表达式的时候断住
- 日志点(logpoint):打印日志但不断住,觉得断住太多次的时候可以用这个
- DOM 断点:在 DOM 子树修改、属性修改、节点删除的时候断住
- Event Listenter 断点:在某个事件发生的时候断住
- url /image/2023 包含某内容的请求时断住
- sourcemap 的原理和作用
- webpack 的 sourcemap 配置
- 调试 React、Vue 源码
- Node.js 的调试
- VSCode Node Debugger 配置
- 调试 Nest.js 源码
- 命令行工具的两种调试
- 调试下 ESLint、Babel、TypeScript 的源码
- Chrome DevTools
- 6 种打断点的方式
- Performance :分析和优化网页性能
- LightHouse :检测页面性能
- Memory:分析内存问题
- 调试移动端网页
- 调试安卓和 ios 的网页
- Charles 的使用
- 调试工具的原理
- 自定义调试工具的实现原理
- 实现一个简易版 React DevTools
- Chrome DevTools 的原理
- 实现 mini puppeteer
- 分别实现 Chrome DevTools 的各个部分的功能
- 自定义调试工具的实现原理
VSCode Debugger 调试 Node.js
TODO
VSCode Node Debugger 配置
TODO
调试 npm scripts
TODO
调试 ESLint、Babel、TypeScript 的源码,Nest.js 源码。
TODO
Chrome DevTools
- 学习 Chrome DevTools 的 7 种打断点的方式
- 用 Performance 工具分析和优化网页性能
- 用 LightHouse 工具检测页面性能
- 用 Memory 工具分析内存问题
- 用 Layers 工具进行图层分析等。
如何调试移动端网页
移动端网页调试离不开代理,所以我们还会学习 Charles 的使用。