【手把手react源码解读】高效阅读react源码的准备工作 ———手把手陪你react源码解读系列

·  阅读 611

前言

有很多人看过很多react源码解读的文章,但是都是别人写好的、截图的知识点。但是自己去看react源码的时候,又被庞大又复杂的项目劝退。 本系列将尝试与大家一起动手开始源码阅读,并同步实践,目标是输出一个属于自己的react。 本系列持续更新react源码解读历程。 拒绝只动眼不动手。 可以随本系列动手开始在自己本地进行实践。

项目地址 github.com/lizuncong/m…

本文主旨

删繁就简,提取react构建之后的核心内容。并能快速对应到源码的位置

下载react源码,并打包到本地

  • git clone下载react源码 github.com/facebook/re…
  • cd react进入react源码目录
  • yarn build react, shared, scheduler, react-reconciler, react-dom --type=NODE
    • 需要java环境
  • cd build/node_modules/react
  • yarn link
  • cd build/node_modules/react-dom
  • yarn link
  • 然后创建一个新项目,比如mini-react
  • 在mini-react中执行yarn link react react-dom即可

react 源码使用 rollup 打包,将所有的模块都打包到一个文件中,比如 react.development.js 以及 react-dom.development.js,没有对应 的 sourcemap,导致阅读源码的过程当中无法得知源码位于哪个文件,如下图中红框内的源码无法映射到原文件,阅读体验不好。

image.png

同时,react 在打包开发环境的代码时,会引入大量的本地调试代码

image.png

这段代码对应的源码在于:packages/react/src/ReactDebugCurrentFrame.js文件中:

image.png

react 源码中大量使用 __DEV__ 环境变量判断(参考:__DEV__说明),如果是开发环境,则括号中的代码会被打包进产物中,如果是生产环境,则不会打包进产物中。这样 可以在开发环境注入一些调试代码,比如检查 props 是否合法、创建 element 的时候是否需要校验参数等情况

image.png

实际上,这些开发时的校验代码与react主流程没有什么关系,我们不关心这些开发时的场景,只需要专注于主流程,因此如果打包时能够减少这部分代码,对我们阅读 体验来说还是相当不错的。

实现

修改 react 源码打包时 rollup 配置,然后终端运行:

yarn build react, shared, scheduler, react-reconciler, react-dom --type=NODE
复制代码

打包完成,复制 build/node_modules/react/cjs/react.development.js 以及 build/node_modules/react-dom/cjs/react-dom.development.js,在本地粘贴,本地调试时可以使用这两份源码

// Remove 'use strict' from individual source files.
{
  transform(source, id) {
    id = id.replace('/Users/lizc/Documents/MYProjects/react/', '')
    let sourceStr = source.replace(/['"]use strict["']/g, '');

    sourceStr = `/***************** debugger ${id} == start *****************/\n${source}\n/***************** debugger ${id} == end *****************/`
    return sourceStr;
  },
},
// Turn __DEV__ and process.env checks into constants.
replace({
  __DEV__: 'false', // isProduction ? 'false' : 'true',
  __PROFILE__: isProfiling || !isProduction ? 'true' : 'false',
  __UMD__: isUMDBundle ? 'true' : 'false',
  'process.env.NODE_ENV': isProduction ? "'production'" : "'development'",
  __EXPERIMENTAL__: false,
  // __EXPERIMENTAL__,
  // Enable forked reconciler.
  // NOTE: I did not put much thought into how to configure this.
  __VARIANT__: bundle.enableNewReconciler === true,
}),
复制代码

image.png

效果

最终,优化后,打包出来的代码体积,react.development.js 从原先的2334行,减少到1122行。react-dom.development.js 从原先的26263行 减少到20600行。

image.png

image.png

image.png

源码拆分

react打包出来的源码都在一份文件中,比如 react-dom 打包后的代码接近2万行,对于我,只要将源码位置信息注入到打包后的代码中,阅读体验就非常好了。有些同学可能还是习惯于将源码映射到不同的文件,那么也可以通过在 rollup 配置中,修改 transform 插件的逻辑,比如:

  transform(source, id) {
    // 修改id
    id = id.replace('/Users/lizc/Documents/MYProjects/react/', '/Users/lizc/Documents/MYProjects/react/dist/')
    let sourceStr = source.replace(/['"]use strict["']/g, '');
    require('fs-extra').outputFile(id, sourceStr)

    return sourceStr;
  },
复制代码

这个时候就会在根目录下生成一个dist文件夹,里面就是源码映射的文件

阅读代码

react.development.js react-dom.development.js 即是需要阅读的内容

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改