React 18源码学习篇02 调试
Published:
在对React整体架构有了基本认识的基础上,学习React源码最直接有效的方式就是亲自调试代码,在关键的代码调用处打断点、查看变量赋值以及函数调用栈等等。而常见的调试工具包括不限于Chrome Sources、 VS Code。根据React源码构建的位置,调试由易到难大致可以划分为三个思路:
- 调试npm registry中的React构建产物
- 调试本地构建的React产物
- 调试React源码和项目代码共同构建的产物
调试npm registry中的React构建产物
通过create-react-app
快速创建react_debug项目,创建完成的项目默认安装了所有依赖项,包括react
和react-dom
的最新版本。执行start
命令后浏览器弹出初始页面,可在Sources
选项卡中对react.development.js
、react-dom.development.js
和scheduler.development.js
进行断点调试。
操作步骤
- 初始化react_debug项目并运行
npx create-react-app react_debug npm run start
此时项目目录结构:
- 浏览器(以Chrome为例)自动弹出页面,打开调试面板并在需要调试的函数如
performUnitOfWork
处增加断点,如下:
总结
这是最简单、省时的调试React源码的方法,几乎不需要额外的配置或其他手动修改源码的操作。在Sources
选项卡中打开要调试的文件并全局搜索需要调试的函数进行断点基本可以满足追踪函数调用栈的需求。这种调试方式的缺点也很明显,1)不能修改源码调试,比如增加日志 2)无法定位到源码的具体文件。对于React源码的初学者推荐用这种方式进行调试,一来可以快速进入、学习源码的具体逻辑,二来降低”魔改“源码过程中产生大量报错产生的挫败感。
调试本地构建的React产物
在第一种调试方法中,react
、react-dom
是React官方构建并发布在npm registry
的包,我们无法进行修改调试。而这个过程可以通过本地发包或者链接的方式进行替换,源码在修改后重新本地发包即可。
操作步骤
在这里,我们通过yalc
本地发包举例。
- fork React的源码到自己的仓库方便修改,拉取到本地
git clone git@github.com:[yourname]/react.git
- 进入react源码的目录并安装依赖
yarn install
- 构建测试环境产物
yarn build-for-devtools-dev
此时react源码目录下新增
build
文件夹,如下
- 切换到需要本地发包的包路径下执行本地发包
yalc publish
- 切换到
react_debug
目录下,执行yalc add react reac-dom
此时
package.json
会变为-- "react": "^18.2.0", -- "react-dom": "^18.2.0", ++ "react": "file:.yalc/react", ++ "react-dom": "file:.yalc/react-dom",
react_debug
目录变为
至此react_debug
项目下的react
和react-dom
包都已切换为本地发布到yalc
中的包。 如果想要修改源码比如在代码中增加日志,可以重新构建react源码,并推送更新到react_debug
- 修改入口函数,增加打印
- 重新构建产物
yarn build-for-devtools-dev
- 切换到需要本地发包的包路径下执行本地发包、推送
yalc push
- 切换到
react_debug
目录下,删除依赖并重新安装后执行yarn start
在浏览器中可以看到控制台已经成功打印我们添加的日志。
总结
相较于第一种调试方法,本地发包的方式在步骤上显得更加繁琐也更加耗时,并且调试的仍然是*.development.js
无法与源码中的文件对应,好处则是可以灵活的修改源码。除了使用yalc
,npm link
也可以达到同样的目的,这里不再演示。
调试React源码和项目代码共同构建的产物
前两种方式的关注点更聚焦在react作为一个第三方库,与react_debug
是互相独立的关系。而这种方式将react源码作为react_debug
项目的一部分,与react_debug
项目共同进行打包。在构建配置项中开启sourcemap
选项后就可以在浏览器Sources
选项卡下打开react源码中对应的文件。
操作步骤
具体操作步骤可参考1。(参考中react源码版本为18.1.0,本文选用18.2.0,在eslint某些选项有所不同,可根据报错信息自行关闭对应规则校验)
具体效果如图所示:
总结
这种调试方法基本解决了源码无法修改以及无法直接定位到源码具体文件的问题。对于react源码有一定的认识后,推荐用这种方式进行调试,更灵活且构建速度更快。
全文总结
作为一个第三方库,调试react在本质上并没有和调试组件库、工具库有什么区别,关键在于我们用什么方式将需要调试的库引入到项目中。另外需要注意的是,我们项目中导入的第三方库大部分都是经过rollup
、webpack
等等工具构建过之后的产物,甚至经过混淆、压缩之后代码已经完全不可读。在dev
模式下,我们可以看到,react源码的构建产物比如react.development.js
、react-dom.development.js
等等仍然具有较好的可读性,所以除了特别需要修改react源码的需要,推荐使用第一种调试方法。其他调试方法可参考23。