如何进行react源码调试
问题
之前调试 react 源码时,都是将 react 打包后进行调试。这种方案虽然也能达到调试的目的,但是相较于直接调试源代码,还是不够直观方便。
思路
将 react 源码作为本地文件引入,然后用 webpack 配合 sourcemap,这样就能跟踪到源代码。但是在这个过程中还有一些任务需要处理。
1.拉取 react 源码
shell
git clone https://github.com/facebook/react.git拿到 react 源代码(后面以目录名react-main为例),其中 packages 目录包含所有 react 相关的包。
2. 新建一个 webpack 打包项目
webpack.config.js配置如下:
javascript
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')
const { DefinePlugin } = require('webpack')
const resolve = target => path.join(__dirname, target)
module.exports = {
// 入口文件目录
entry: [
'./src/index.js'
],
module: {
rules: [
// 处理 js 文件
{
test: /\.js$/,
include: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
// 添加 react 和 flow preset,用于解析 flow 和 react 语法
presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-flow'],
}
}
}
]
},
resolve: {
alias: {
// 这里可以添加一些自己想要调试的源码包,路径为我们 clone 的源代码路径
'react': resolve('../react-main/packages/react'),
'react-dom': resolve('../react-main/packages/react-dom'),
'react-reconciler': resolve('../react-main/packages/react-reconciler'),
}
},
plugins: [
new HtmlWebPackPlugin({
template: './index.html',
filename: './index.html'
}),
// 在 `react` 中会有一些环境变量,这里需要单独去设置。
new DefinePlugin({
'__DEV__': true,
'__PROFILE__': false,
'__EXPERIMENTAL__': true,
'__UMD__': true
}),
],
devServer: {
static: './dist',
port: 8080,
},
// 设置 sourcemap,用于关联源代码。
devtool: 'source-map',
hot: true,
mode: 'development'
}其中需要安装的开发包有:
json
{
"devDependencies": {
"@babel/core": "^7.17.5",
"@babel/preset-env": "^7.16.11",
"@babel/preset-flow": "^7.16.7",
"@babel/preset-react": "^7.16.7",
"babel-loader": "^8.2.3",
"html-webpack-plugin": "^5.5.0",
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"
}
}处理 react 报错
在实际运行时,react 内还有一些变量方法由于没有“进行打包”会报错,需要手动进行处理。
修改 ReactSharedInternals
修改 /react-reconciler/src/ReactFiberHostConfig.js,原有内容注释掉, 添加一行:
javascript
export * from './forks/ReactFiberHostConfig.dom';关闭函数 invariant
修改 /shared/invariant.js,直接 return。不让报错:
javascript
export default function invariant(condition, format, a, b, c, d, e, f) {
return
throw new Error(
'Internal React error: invariant() is meant to be replaced at compile ' +
'time. There is no runtime version.',
);
}将 React 和 ReactDOM 默认导出
react/index.js:
javascript
import * as React from './src/React'
export default Reactreact-dom/index.js:
javascript
import * as ReactDOM from './src/client/ReactDOM'
export default ReactDOMchrome 调试
最后正常启动 webpack 项目,在 chrome 的 source 目录中就可以调试源代码了。
vscode 调试
详情参见 vscode 的 debug 插件。仅需点击运行的命令链接即可在 vscode 中调试。
