什么?调试 React 源码还有优雅和不优雅之分?

别着急,我们先来听个故事:

东东是一名前端工程师,主要用 React 技术栈,用了多年之后想深入一下,所以最近开始看 React 源码。

他把 react 和 react-dom 包下载了下来,在项目里引入,开发服务跑起来后,打开 Chrome Devtools 打断点调试。

这样调试了一段时间之后,他有了一些困惑:

这样调试是可以的,但是总感觉和源码有段距离,因为调试的是 react-dom.development.js

而源码里这些逻辑是分散在不同的包里的,所以就算搞懂了逻辑,也不知道这些逻辑在哪些包里,只能靠搜索来定位。

所以他就在想,是不是有更好的调试方式,能够调试 React 最初的源码呢?

于是,他跑来问我:光哥,你调试 React 源码会有这些问题么?你是怎么调试的呀?

我说,确实,我最开始也是调试的 react-dom.development.js,但是现在已经能直接调试 React 最初的源码了,而且是在 VSCode 里调试的,点击调用栈能直接打开对应的 React 源码文件并定位到对应行列号:

哇哦,这就是我想要的调试效果,这是怎么做到的呀。

想实现这样的调试效果确实还有点复杂,我们一点点来看:

首先,我们要做到在 VSCode 里调试 React 项目,而不是在 Chrome Devtools 里,这样才能做到直接打开对应的文件:

用 VSCode 调试 React 项目

我们用 create-react-app 创建一个 react 项目,然后 npm run start 跑起来。

这时候浏览器访问就可以用 Chrome Devtools 调试了:

但我们的目标是在 VSCode 里调试,所以要添加一个 VSCode 的 debugger 配置:

在根目录下建一个 .vscode/launch.json 的文件,添加一个 chrome 类型的调试配置,输入调试的 url。

然后点击 debug 启动:

这时候就可以在 VSCode 里直接打断点调试了:

用 VSCode 调试肯定会比 Chrome Devtools 方便一些。但这不是我们最主要的目的,现在调试的依然是 react-dom.development.js:

那怎么调试 react 最初的源码呢?

这就涉及到 sourcemap 的作用了:

sourcemap

JS 代码经过编译,会产生目标代码,但同时也会产生 sourcemap。sourcemap 的作用就是映射目标代码中的位置和源码中的位置。

比如源码中的第 3 行第 5 列的代码对应着编译后的第 1 行第 10 列的代码。

类似这样的映射有很多,经过编码以后是这样的:

在 js 文件最后一行,加上这样一行注释就可以关联 sourcemap:

//# sourceMappingURL=http://example.com/path/to/your/sourcemap.map

调试工具支持解析 sourcemap 来映射调试的代码位置到源代码中的位置。

比如 chrome devtools 的 Sources 面板就会提示从哪个文件 source mapping 过来的,点击链接还可以跳到映射之前的文件:

同样,VSCode Debugger 也支持 sourcemap,有个 sourceMaps 的调试配置选项来开启和关闭 sourcemap 功能,默认开启。

那这么说我们只要让 react-dom.development.js 关联上 sourcemap,就能调试最初的 React 源码了?

理论上是这样的,但是现在下载的 react、react-dom 包里都不带 sourcemap,我们得把 React 源码下载下来自己 build:

build 出带有 sourcemap 的 react 包

用 npm 下载的 react 包是这样的:

而我们需要的是带有 sourcemap 的代码,也就是这样的:

这就要下载 react 源码自己 build 了:

git clone https://github.com/facebook/react

下载下来的代码执行 npm run build 就能看到 build 的产物:

这里的 build/node_modules 下的 react 和 react-dom 包就是我们需要的。

但是现在 build 出的代码并没有带 sourcemap,需要改造下 build 流程。

build 命令执行的是 ./scripts/rollup/build.js,打开这个文件做一些修改。

找到 rollup 的配置,添加一行 sourcemap: true,这个很容易理解,就是让 rollup 在构建时产生 sourcemap:

再跑 npm run build,会报这样的错误:

某个转换的插件没有生成 sourcemap。

这个是因为构建的过程中会进行多次转换,会生成多次 sourcemap,然后把 sourcemap 串联起来就是最终的 sourcemap。如果中间有一步转换没有生成 sourcemap,那就断掉了,也就没法把 sourcemap 串联起来了。

这个问题的解决只要找出没有生成 sourcemap 的那几个插件注释掉就可以了:

在 getPlugins 方法里,把这样 4 个插件给注释掉:

这个是删除 use strict 用的,可以去掉。

这个是生产环境压缩代码的,也可以去掉。

这个是用 prettier 格式化代码的,也可以去掉。

这个是添加一些头部的代码的,比如 Lisence 等,也没啥用,可以去掉。

去掉这四个插件之后,再运行 npm run build,这时候就能正常进行构建了,然后产生的代码就是带有 sourcemap 的:

这样我们就成功的 build 出了带有 sourcemap 的 react 包!

接下来只剩最后一步,用上 sourcemap,实现直接调试 React 最初的源码,

应用 sourcemap,调试 React 最初的源码

我们已经 build 除了带有 sourcemap 的 react 和 react-dom 包,那把这俩包复制到测试项目的 node_modules 下,就可以直接调试最初的源码了么?

还是不行。

为什么呢?

看下面这张图:

我们改造了 build 流程,对 react 源码进行了 build,产生了带有 sourcemap 的 react、react-dom 包,这些包最终导出的是 react-xx.development.js。

之后在项目里引入,经过 webpack 打包,产生了 bundle.js 和 sourcemap。

之后调试工具运行代码的时候,会解析 sourcemap,完成从 bundle.js 到 react-xxx.development.js 的映射:

但是并不会再次做 react-xx.development.js 到 react 最初源码的映射呀。

也就是调试工具只会解析一次 sourcemap。

那怎么办呢?

不打包 react 和 react-dom 这俩包不就行了。不经过 webpack 打包,那就没有 webpack 产生的 sourcemap,不就一次就映射到 React 最初的源码了么。

那怎么不打包这俩模块呢?

webpack 支持 externals 来配置一些模块使用全局变量而不进行打包,这样我们就可以单独加载 react、react-dom,然后把他们导出的全局变量配置到 externals 就行了。

要改动 webpack 配置的话,在 create-react-app 下要执行 npm run eject。

然后项目下会多出 config 目录和 public 目录,这俩分别放着 webpack 配置和一些公共文件。

修改 webpack 配置,在 externals 下添加 react 和 react-dom 包对应的全局变量:

然后把 react.development.js 和 react-dom.development.js  放到 public 下,并在 index.html 里面加载这俩文件:

这样再重新 debug,你就会发现 sourcemap 映射到 React 最初的源码了:

不再是 react-dom.development.js 下的代码,而是具体 react-xxx 包下的。

这就达到了最开始的目的,能直接调试 React 最初的源码!

还记得我们这样做的意义么?

能调试最初的源码才能知道哪段逻辑是在哪个包里的,不然要自己去搜索。

这样已经能够达到我们的目的了,但是要想点击调用栈直接定位到 git clone 下来的 react 项目的文件,还需要再做一步。

关联 react 源码项目

看我最初演示的效果,点击调用栈是能直接定位到 react 源码项目的文件的:

这是怎么做到的呢?

其实只要 sourcemap 生效,并且 map 到的文件是在当前 workspace 下,VSCode 就会打开对应的文件。

现在 sourcemap 已经生效了,只不过 react 项目没有在 workspace 下。所以,如果想直接定位 react 源码项目的话,可以这样做:

创建一个新的目录,把 react 源码项目和测试的项目放到一个 workspace 下,这样再调试的时候,map 到的文件就能在 workspace 找到了,也就会打开相应的文件。

只不过现在 sourcemap 下都是这样的相对路径,会导致映射到的文件路径不对:

所以再去修改下 react build 流程,在 ./script/rollup/build.js 下,添加一个 sourcemap 的路径映射,把 ../../../packages 映射到 react 项目的绝对路径/pcakges :

这时候再重新 build,生成的 sourcemap 就是绝对路径了:

把新生成的 sourcemap 复制过去,覆盖一下。

在新的 workspace 里 debug,你就会发现,路径映射对了:

点击调用栈能直接打开 react 源码项目的对应文件了!

至此,我们就能优雅的调试 React 最初的源码了。

总结

用了 react 比较长时间后,自然会想调试下源码来深入下,但是常规的调试方式只能调试 react-dom.development.js,虽然能理清逻辑,但是对应不到源码里的哪些包哪些文件,总感觉和最初的源码还有一段距离。

这个问题是有解决方案的,就是会有点复杂:

首先要把 react 源码项目下载下来,修改 build 流程来生成带有 sourcemap 的 react 和 react-dom 包,并且修改 sourcemap 映射的路径为绝对路径。

然后把 react 和 react-dom 配置到 webpack 的 externals 里,不进行打包,而是单独在 index.html 里引入。

因为 sourcemap 只会映射一次,而 webpack 已经生成了一次 sourcmap,只有跳过这俩模块的打包才能让 react 和 react-dom 的 sourcemap 生效。

之后用 VSCode Debugger 来调试 React 项目,就能映射到最初的 React 源码了。

如果想点击调用栈直接打开对应 React 源码项目的文件,那就新建一个 workspace,把测试项目和 React 源码项目包含就行了。因为 VSCode 如果在 workspace 下找到了 source map 到的文件,就会直接打开对应的文件。

东东:最终的调试效果是很完美,但这个流程有点复杂

我:确实,想实现能调试最初的源码,并且还能直接打开对应的 react 源码项目的文件,还是比较麻烦的,但好在只需要配置一次,以后就能一直用了,而且类似的源码调试方式也可以应用到其他源码的调试。

毫不夸张地说,这应该是全网最优雅的 React 源码调试方式了。

- END -

关于奇舞团

奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

全网最优雅的 React 源码调试方式相关推荐

  1. webuploader 怎么在react中_另辟蹊径搭建阅读React源码调试环境支持所有React版本细分文件断点调试...

    引言(为什么写这篇文章) 若要高效阅读和理解React源码,搭建调试环境是必不可少的一步.而常规方法:使用react.development.js和react-dom.development.js调试 ...

  2. 全网最简单的dubbo源码调试,建议点赞收藏!!!

    dubbo这两年非常的火,那光知道怎么用不行,我这章就告诉你们最简单搭建dubbo源码的方法,记得收藏!! 1.准备环境 IDEA你随便 Maven 3.5.6及以上版本 Dubbo源码版本2.7.3 ...

  3. react map循环生成的button_【第1945期】彻底搞懂React源码调度原理(Concurrent模式)...

    前言 估计会懵逼.今日早读文章由成都@苏溪云投稿分享. 正文从这开始~~ 最早之前,React还没有用fiber重写,那个时候对React调度模块就有好奇.而现在的调度模块对于之前没研究过它的我来说更 ...

  4. Windows驱动开发二:Windbg源码调试

    在windbg中源码调试,编译好测试的驱动文件到指定路径打开 windbg-> Open source file 打开 在原代码文件同级目录中有编译打符号文件,Settings->Defa ...

  5. build怎么调试 react_GitHub - bozhouyongqi/debug-react: 本地调试react源码环境

    [TOC] 工欲善其事,必先利其器. 在学习raect源码时,如果能够在浏览器中单步调试,势必会加深理解.其实可以借助webpack的resolve.alias将react等指向本地的目录,这样就不会 ...

  6. React源码分析与实现(一):组件的初始化与渲染

    原文链接地址:github.com/Nealyang 转载请注明出处 前言 战战兢兢写下开篇...也感谢小蘑菇大神以及网上各路大神的博客资料参考~ 阅读源码的方式有很多种,广度优先法.调用栈调试法等等 ...

  7. 推荐一个 React 技术揭秘的项目,自顶向下的 React 源码分析

    大家好,我是你们的 猫哥,那个不喜欢吃鱼.又不喜欢喵 的超级猫 ~ just-react 这本书的宗旨是打造一本严谨.易懂的 React 源码分析教程. 为了达到这个目标,在行文上,本书会遵循: 不预 ...

  8. React 源码剖析系列 - 解密 setState

    this.setState() 方法应该是每一位使用 React 的同学最先熟悉的 API.然而,你真的了解 setState 么?先看看下面这个小问题,你能否正确回答. 引子 class Examp ...

  9. 人人都能读懂的react源码解析(大厂高薪必备)

    人人都能读懂的react源码解析(大厂高薪必备) 1.开篇(听说你还在艰难的啃react源码) ​ 本教程目标是打造一门严谨(严格遵循react17核心思想).通俗易懂(提供大量流程图解,结合demo ...

最新文章

  1. 集成学习(Bagging和AdaBoost和随机森林(random forest))
  2. 中南大学计算机网.doc,中南大学计算机网络实验报告.doc
  3. vue 安装指定版本swiper_Vue中的runtime-only和runtime-compiler
  4. 计算机平面设计专业有哪些课程,计算机平面设计专业课程有哪些?
  5. 本周三、四两场直播丨达梦 vs. Oracle,从快速入门到性能分析优化
  6. html轮播图显示失败_html简单的二级菜单制作
  7. 5 helloword 开发运行步骤
  8. ncbi下载数据sra和转换fastq流程
  9. 数据库建模工具PowerDesigner的基本使用方法
  10. 女生干前端开发个人思考
  11. 数据挖掘:数据清洗——缺失值处理
  12. 云知声语音语义识别,语音唤醒和语音合成简单工具类封装
  13. linux解除硬盘加密,linux下硬盘加密
  14. 码洞原创深度技术文章大全 —— 高端面试必备
  15. 游戏里面的模型是怎么制作的?次世代场景建模有哪些特点?
  16. RFID技术在智能超市中的应用
  17. 计算机专业考研要分最低的院校,计算机考研院校难度排行榜
  18. MQTT.fx连接RabbitMQ-MQTT出现bad user name or password问题
  19. execve()函数的研究
  20. 初等数学建模问题-贷款问题(1)

热门文章

  1. 使用Python完成公司名称和地址的模糊匹配
  2. caxa齿轮零件图_齿轮油泵-各零件图
  3. 面向对象中的聚合与耦合的区别
  4. 太香了,这100 个 Python 代码案例非常适合初学者练习
  5. 一日一技:别怕,我们的聊天消息,没人能偷看
  6. 网络***实战:老Y文章管理系统V2.2注入漏洞分析与利用
  7. 英语口语/高级口语——话题vs备考资料
  8. JNPF快速开发平台 3.4.1 3.3.1 3.3.2 企业版旗舰版 框架源码 大屏设计 大屏源码
  9. 初涉openGL遇显卡问题【解决方案】
  10. 4米乘以12米CAD图_如何让你的CAD复杂地形秒变SU模型