React源码调试

最近看了很多react源码的讲解视频、文章,不过纸上得来终觉浅,看一百次不如自己调试一次印象来得深。

拉取react源码安装依赖

js 复制代码
git clone https://github.com/facebook/react.git
yarn

拉取源码后可以看到react的模块都放在packages目录下,因为react的类型检查用的是flow,肯定是不能直接运行在浏览器里的所以我们需要使用babel转换成普通的js。packages下有许多模块有的模块涉及到服务端渲染、开发工具、跨平台,这里我们只需要浏览器相关的模块 react react-client react-dom react-dom-bindings react-reconciler scheduler shared 接下来就可以使用babel转换这些模块,转换的时候会遇到报错有些报错文件并不会转换成功,先不用管,后面启动项目时遇到缺少的文件或目录再一一单独转换就行

js 复制代码
// 这里只举例了react, 上述其他模块也是如此
./node_modules/.bin/babel ./packages/react --out-dir ./build/react

启动项目

  1. 先创建一个react项目,然后把react源码build目录拷到react-debug下改名为react-source。
js 复制代码
pnpm create vite react-debug --template react
  1. 修改vite.config.js
js 复制代码
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    // 修改 jsx 方法的引用路径,会指向到react-source/react/jsx-dev-runtime.js
    react({
      jsxRuntime: "automatic",
      jsxImportSource: path.resolve(import.meta.dirname, "react-source/react/"),
    }),
  ],
  // 定义react中的变量
  define: {
    __EXPERIMENTAL__: false,
    __PROFILE__: false,
    __DEV__: false,
  },
  resolve: {
  // 设置文件系统别名
    alias: [
      {
        find: "react",
        replacement: path.resolve(import.meta.dirname, "react-source/react/"),
      },
      {
        find: /^react-dom\/(.*)?/,
        replacement: path.resolve(
          import.meta.dirname,
          "react-source/react-dom/$1"
        ),
      },
      {
        find: /^react-source\/(.*)?/,
        replacement: path.resolve(import.meta.dirname, "react-source/$1"),
      },
      {
        find: /^react-dom-bindings\/(.*)?/,
        replacement: path.resolve(
          import.meta.dirname,
          "react-source/react-dom-bindings/$1"
        ),
      },
      {
        find: /^shared\/(.*)?/,
        replacement: path.resolve(
          import.meta.dirname,
          "react-source/shared/$1"
        ),
      },
      {
        find: /^react-reconciler\/(.*)?/,
        replacement: path.resolve(
          import.meta.dirname,
          "react-source/react-reconciler/$1"
        ),
      },
      {
        find: "scheduler",
        replacement: path.resolve(
          import.meta.dirname,
          "react-source/scheduler/"
        ),
      },
      {
        find: /^react-client\/(.*)?/,
        replacement: path.resolve(
          import.meta.dirname,
          "react-source/react-client/$1"
        ),
      },
    ],
  },
});
  1. 修改 react/src/jsx/ReactJSX.js。(PS: 可能会因为在第一步执行babel失败在react-source中并没有jsx目录,再到react源码中执行 ./node_modules/.bin/babel ./packages/react/src/jsx --out-dir ./build/react/src/jsx然后再把jsx目录复制到react-source就行了,其他babel执行失败的文件也是一样 )
js 复制代码
// react-source/react/src/jsx/ReactJSX.js 
var jsxDEV = __DEV__ ? _jsxDEV : jsxProd
  1. 把引入路径都成从 react-source 中引入
js 复制代码
// App.jsx
import { useState } from "react-source/react"

function App() {
  const [count, setCount] = useState(0)
  return (
    <div>
      I am React
      <button onClick={() => {
        setCount(count + 1)
      }}>{count}</button>
    </div>
  )
}

export default App
  1. 最后就可以开始"愉快"得调试源码啦,现在在createRoot的地方打断点就会进到react-source里了
相关推荐
阿华的代码王国13 分钟前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼13 分钟前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy17 分钟前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT31 分钟前
promise & async await总结
前端
Jerry说前后端32 分钟前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化
画个太阳作晴天39 分钟前
A12预装app
linux·服务器·前端
7723891 小时前
解决 Microsoft Edge 显示“由你的组织管理”问题
前端·microsoft·edge
烛阴1 小时前
前端必会:如何创建一个可随时取消的定时器
前端·javascript·typescript
JarvanMo2 小时前
Swift 应用在安卓系统上会怎么样?
前端
LinXunFeng2 小时前
Flutter - 详情页 TabBar 与模块联动?秒了!
前端·flutter·开源