React 源码调试方式

目录
  • 正文
  • 断点调试
  • 搜索定位
  • Chrome Devtools 调试
  • sourcemap
  • npm 下载react包
  • 插件注释
  • 调试 React 最初源码
  • 关联 react 源码项目
  • 总结

正文

什么?调试 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 调试

这时候浏览器访问就可以用 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包

用 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 包!

调试 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 源码调试方式了。

以上就是React 源码调试方式的详细内容,更多关于React 源码调试的资料请关注我们其它相关文章!

(0)

相关推荐

  • 使用VScode 插件debugger for chrome 调试react源码的方法

    代码调试,是我们前端日常工作中不可或缺的能力了吧! 在面向dom开发的时代,我们开发时直接在chrome里打断点是很方便的. 但是,当我们面向组件开发时(react),浏览器拿到的是我们编译过后的代码,还想在浏览器里打断点几乎是不可能的了. 场景 那怎么办,方法总是比困难多!愚蠢的我想到了console/debugger!!一直在使用,虽然很不方便(打印太多实在太乱!上线还要配置删除掉),但是我竟然使用了很久(这真是一个糟糕的编码习惯吧).直到今天,我想研究一下react源码,需要断点的地方有很

  • 解决VSCode调试react-native android项目错误问题

    如果运行react-native android项目出现如下错误: 解决办法如下: 一.执行adb devices,判断adb有没有断, 二.如果是adb断了就使用一下步骤 adb reverse tcp:8081 tcp:8081 npm start 如果adb没断,直接 npm start 如果执行gradle ass打包命令进行打包之后,出现如下错误: 1.检查react-native项目工程目录下的index.js里面的AppRegistry.registerComponent(appN

  • 从零搭建Webpack5-react脚手架的实现步骤(附源码)

    目录 webpack5 正式开始 搭建指南 开始搭建 完成了依赖的准备工作,开始搭建项目 编写webpack.dev.js开发配置 开始编写webpack.prod.js生产配置 编写scripts命令 配置代码质量管控流程 单元测试 webpack5 近期终于有时间和精力专注于公司技术基础建设了,于是一开始,将公司的Saas系统改造成了微前端模式,解决了历史遗留的一部分问题 接着,想着webpack5已经发布这么久了,该在生产环境用起来了,也顺势想推动微前端.webpack5.vite在业内的

  • VS Code开发React-Native及Flutter 开启无线局域网安卓真机调试问题

    笔者前段时间在做react-native开发,一直是有线连接安卓真机进行调试的.有线调试确实带来诸多麻烦,因为在调试过程中需要频繁和手机进行交互,导致有时候数据线脱落,就不得不重新安装debug apk,安装一次应用的时间大概在一到三分钟,大量的误触就使得花在安装应用花费的时间比较长.这几天在研究flutter,就上网搜了一下vscode 开发 flutter开启无线调试.然后顺藤摸瓜,把react-native的无线调试也试了一下. 参考文章:vscode通过wifi调试真机的Flutter应

  • VSCode使React Vue代码调试变得更爽

    目录 引言 用 VSCode 调试 React 代码 用 VSCode 调试 Vue 代码 总结 引言 作为前端开发,基本每天都要调试 Vue/React 代码,不知道大家都是怎么调试的,但我猜大概有这么几种: 不调试,直接看代码找问题 console.log 打印日志 用 Chrome Devtools 的 debugger 来调试 用 VSCode 的 debugger 来调试 不同的调试方式效率和体验是不一样的,我现在基本都是用 VSCode debugger 来调试,效率又高.体验又爽.

  • React 源码中的依赖注入方法

    一.前言 依赖注入(Dependency Injection)这个概念的兴起已经有很长时间了,把这个概念融入到框架中达到出神入化境地的,非Spring莫属.然而在前端领域,似乎很少会提到这个概念,难道前端的代码就不需要解耦吗?前端的代码就没有依赖了?本文将以 React 的源码为例子,看看它是如何使用依赖注入这一设计模式的. 二.依赖注入的基本概念 在看代码之前,有必要先简单介绍一下依赖注入的基本概念.依赖注入和控制反转(Inversion of Control),这两个词经常一起出现.一句话表

  • React 源码调试方式

    目录 正文 断点调试 搜索定位 Chrome Devtools 调试 sourcemap npm 下载react包 插件注释 调试 React 最初源码 关联 react 源码项目 总结 正文 什么?调试 React 源码还有优雅和不优雅之分? 别着急,我们先来听个故事: 东东是一名前端工程师,主要用 React 技术栈,用了多年之后想深入一下,所以最近开始看 React 源码. 断点调试 他把 react 和 react-dom 包下载了下来,在项目里引入,开发服务跑起来后,打开 Chrome

  • Vue3.x源码调试的实现方法

    几句话说下我看源码的方式 断点调试 根据demo小例子或者api的使用姿势进行调试,每个小例子只关心其走过的逻辑分支. 如何调试vue3.x的ts源码 官网说使用 yarn dev 命令就可以对其进行调试,可是运行该命令后,是生成过后的代码,不能对其编写的ts源码进行调试. 其实再生成对应的sourcemap文件,便可以原汁原味的调试. 先看下几个截图: 如果这是你想要的调试效果,下面请看下如何生成sourcemap文件. 生成sourcemap文件 rollup.js中文文档 // rollu

  • Idea中tomcat启动源码调试进入到tomcat内部进行调试的方法

    使用idea开发工具调试代码的时候,如果是java的web项目,使用的是tomcat作为web容器,打断点debug调试跟踪,当跟踪到org.apache.catalina包下的时候,则无法进入,这是因为idea运行的tomcat是通过插件的方式集成的,tomcat里面的lib包不再项目的依赖路径中,所以不能跟踪进去 首先在自己项目中被tomcat回调的接口实现类中,标记一个断点信息,通过idea启动web项目,当出现如图所示的断点信息的时候,因为断点位置标记的是tomcat回调的接口类,所以按

  • OpenJDK源码调试图文教程

    前言      随着Java生态愈发庞大,各种各样的新技术层出不穷,这也给大家的学习带来了很多困惑,这么多技术我该学什么,盲目的在各种新技术间穿梭,并不能取得很好的效果.      作为Java核心技术的JDK相信很多同学都看过源码,了解过Java的内存模型,但是很多时候debug到最后都是 native,这是让人很沮丧的事情,于是乎了解JDK底层的实现变得极为重要.     编译OpenJDK源码的文章很多,但是很少有从头到尾搭建环境的文章,于是我这里就写了这篇文章,这里涉及的主要步骤: 虚拟

  • 详细聊聊React源码中的位运算技巧

    目录 前言 几个常用位运算 按位与(&) 按位或(|) 按位非(-) 标记状态 优先级计算 总结 前言 这两年有不少朋友和我吐槽React源码,比如: 调度器为什么用小顶堆这种数据结构,直接用数组不行? 源码里各种单向链表.环状链表,直接用数组不行? 源码里各种位运算,有必要么? 作为业务依赖的框架,为了提升一点点运行时性能,React从不吝惜将源码写的很复杂. 在涉及状态.标记位.优先级操作的地方大量使用了位运算. 本文会讲解其中比较有代表性的部分.学到之后,当遇到类似场景时露一手,你就是业务

  • spring framework源码调试技巧

    目录 1. 获取spring-framework源码 2. 导入到IDEA 2.1 预编译spring-oxm 2.2 导入到Idea 3 添加用于测试的SpringMVC项目Module 3.1 创建Module 3.2 添加对spring-webmvc的依赖 3.3 添加MVC相关文件 3.4 设置Artifacts 3.5 配置Tomcat服务 3.6 添加json解析: 4. 遇到的问题 4.1 gradle进行build的时候,中文出现乱码: 4.2 gradle项目,用了lombok

  • Go语言编译原理之源码调试

    目录 前言 Goland的debug调试Go源码 dlv工具调试Go源码 安装 常用命令 dlv调试抽象语法树构建 前言 在前边几篇文章中分享了Go编译过程中的源码实现,本文主要是想分享一下我是怎么调试Go的源代码的(如果你很熟悉的话,可以跳过本文).本文主要是分享两种Go源码的调试方法 Goland的debug dlv工具 本文我还会以抽象语法树为例,来通过dlv对它的构建过程进行调试 Goland的debug调试Go源码 下边以调试Go编译的入口文件为例 编辑debug配置 填写配置信息 打

  • react源码层分析协调与调度

    目录 requestEventTime requestUpdateLane findUpdateLane lanePriority LanePriority createUpdate enqueueUpdate 总结 协调与调度 reconciler流程 同步任务类型执行机制 异步任务类型执行机制 shouldYield performUnitOfWork beginWork completeUnitOfWork scheduler流程 performWorkUntilDeadline 总结 r

  • react源码合成事件深入解析

    目录 引言 导火线 事件委托 合成事件特点 React 事件系统 事件注册 enqueuePutListener() listenTo() trapCapturedEvent 与 trapBubbledEvent 事件存储 事件分发 事件执行 构造合成事件 批处理 引言 温馨提示: 下边是对React合成事件的源码阅读,全文有点长,但是!如果你真的想知道这不为人知的背后内幕,那一定要耐心看下去! 最近在做一个功能,然后不小心踩到了 React 合成事件 的坑,好奇心的驱使,去看了 React 官

随机推荐