什么?调试 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 里,这样才能做到直接打开对应的文件:
我们用 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 的作用了:
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:
用 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 最初的源码,
我们已经 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 源码项目的文件的:
这是怎么做到的呢?
其实只要 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 -
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/ldqh7iq-gFQMQ8iXAEg3QQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。