一、前言
你是否有这样的疑惑?明明代码写错了,却能正常的运行;你觉得代码写的是正确的,却报了个 error。你绞尽脑汁,发挥毕生之所学,却始终不得其解。
来吧!调试源码吧!从源码的执行流程中,找到问题本质。
二、创建测试项目
为了专注于源码调试,所以我从0到1创建一个webpack-dev项目。
// 开发环境:
os: win11 x64
node: v16.10.0
java: 11.0.18
1、初始化项目
- npm init -y
- pnpm add react@16.8.6 react-dom@16.8.6
- pnpm add -D webpack webpack-cli webpack-dev-server
- pnpm add -D @babel/core babel-loader html-webpack-plugin
- pnpm add -D @babel/preset-env @babel/preset-react
然后,在package.json文件中增加一个命令:
"dev": "webpack serve"
2、创建一个src文件夹,下面建立index.js
import React, { useEffect } from 'react'
import ReactDom from 'react-dom'
function App() {
useEffect(() => {
console.log('useEffect')
}, [])
return <div>111</div>
}
ReactDom.render(<App />, document.getElementById('root'))
3、根目录下新增 webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'production',
entry: './src/index.js',
devServer: {
port: 10001
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
]
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'react',
template: 'index.html'
})
],
// 取消入口文件大小限制
performance: {
hints: false
},
}
4、根目录下新建index.html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<div id="root"></div>
</body>
</html>
5、测试运行
执行:pnpm dev
结果如下:
三、调试源码
在当前目录下,使用git clone拉下来React的远程仓库代码。代码体积很大,约几百兆,需要稍微等一会儿。
1、切换到16.8.6的源码
cd react 进入源码目录,然后使用 git checkout -b 16.8.6 v16.8.6 命令,基于v16.8.6 这个tag创建自己的测试分支。
2、修改源码打包配置,以生成sourcemap
sourcemap 是用来映射编译后代码在源码中位置的文件。有了它,我们在调试时可以直接查看源代码。
下面,修改/scripts/rollup/build.js中文件:
滑到页面最底部,注释掉除了dev包之外的其他打包配置:
接下来,我们开启sourcemap:
找到getRollupOutputOptions函数位置,修改sourcemap: true
下面,我们还需要注释掉格式化代码的一些配置项,不然生成sourcemap过程中会报错。
找到getPlugins这个函数,注释掉下面的内容
好了,接下来,修改package.json文件中的 devEngines
然后执行:
yarn
yarn build
打包后文件存放在react/build下面。我们将要用到的是react-development.js和react-dom-development.js这两个文件。
3、让测试项目引用源码构建的react、react-dom产物
我们回到根目录,修改webpack.config.js文件。
配置externals去避免打包时引入react、react-dom。
配置devServer下的static属性设置静态资源目录,映射到源码打包产物目录。
// webpack.config.js
...
devServer: {
port: 10001,
static: path.join(__dirname, './react/build/node_modules')
},
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
...
然后,记得修改index.html文件来引入react、react-dom。
<script src="./react/umd/react.development.js"></script>
<script src="./react-dom/umd/react-dom.development.js"></script>
运行 pnpm dev
4、调试源码
这里,我们使用VsCode自带的调试程序。按照下图两个流程走下来,会在根目录创建一个.vscode目录,目录中有个launch.json文件就是调试程序的配置项了。
我们给
src/index.js文件打上一个断点,然后点击调试按钮,就可以开始调试了。
4、映射到源码文件
经过上面的一些列操作,虽然可以直接查看源码,但是我们不能打开当前调试步骤中源码的位置。只是一个模拟的地址。
这是因为,sourcemap文件中, 源码地址使用的相对地址
../../../../packages。这样去映射到硬盘中,对应的位置文件不存在,就会给个模拟的假地址。
我们需要替换两个sourcemap文件中../../../../packages为C:/.../packages,即绝对地址,就像下面这样:
此时再去点击调试,一步步执行下去,可以成功看到当前步骤在源码目录中的位置了!