搭建React源码调试环境

4,143 阅读2分钟

写在前面

  • React源码版本:V17.0.2
  • 日期:2021-3-16 17:17:17
  • create-react-app 搭建

参考:

github.com/nannongrous… github.com/bubucuo/Deb…

1. 搭建项目

npx create-react-app debug-react
cd debug-react
npm run eject

2. 克隆源码 v17.0.2

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

3. 将源码放在 src 目录下 debug-react/src

4. 修改 webpack alias 配置文件 debug-react/config/webpack.config.js

resolve: {
    alias: {
        'react-native': 'react-native-web',
        'react': path.resolve(__dirname, '../src/react/packages/react'),
        'react-dom': path.resolve(__dirname, '../src/react/packages/react-dom'),
        'shared': path.resolve(__dirname, '../src/react/packages/shared'),
        'react-reconciler': path.resolve(__dirname, '../src/react/packages/react-reconciler'),
    }    
}

启动项目,根据提示修改以下配置

5. 配置webpack和eslint中的全局变量

修改/config/env.js:

const stringified = {
    // 保留原有配置...,
    "__DEV__": true,
    "__PROFILE__": true,
    "__UMD__": true
};

根目录下新建.eslintrc.json文件:

{
  "extends": "react-app",
  "globals": {
      "__DEV__": true,
      "__PROFILE__": true,
      "__UMD__": true
  }
}

6. 修改源码内文件:

/src/react/.eslintrc.js

`extends: []` 数组置空

删掉 `/src/react/.eslintrc.js` 文件中所有 `no-for-of-loops`, `no-function-declare-after-return`。

在 `/src/react/` 下搜索 `react-internal`,把包含 `react-internal``注释行``代码行`全部删掉。

/src/react/packages/react-reconciler/src/ReactFiberHostConfig.js

// 注释掉
// import invariant from 'shared/invariant';
// invariant(false, 'This module must be shimmed by a specific renderer.');

// 添加此行
export * from "./forks/ReactFiberHostConfig.dom";

/src/react/packages/shared/ReactSharedInternals.js

// 注释掉
/* import * as React from 'react';

const ReactSharedInternals =
  React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; */

// 添加此行
import ReactSharedInternals from '../react/src/ReactSharedInternals';

export default ReactSharedInternals;

/src/react/packages/shared/invariant.js

export default function invariant(condition, format, a, b, c, d, e, f) {
  // 添加此行
  if (condition) return;

  throw new Error(
    "Internal React error: invariant() is meant to be replaced at compile " +
      "time. There is no runtime version."
  );
}

/src/react/packages/react-dom/src/client 下新建 util.js 文件

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

export const isPrimaryRenderer = true;
export const warnsIfNotActing = true;

// This initialization code may run even on server environments
// if a component just imports ReactDOM (e.g. for findDOMNode).
// Some environments might not have setTimeout or clearTimeout.
export const scheduleTimeout: any =
  typeof setTimeout === 'function' ? setTimeout : (undefined: any);
export const cancelTimeout: any =
  typeof clearTimeout === 'function' ? clearTimeout : (undefined: any);
export const noTimeout = -1;

// -------------------
//     Microtasks
// -------------------
export const supportsMicrotasks = true;
export const scheduleMicrotask: any =
  typeof queueMicrotask === 'function'
    ? queueMicrotask
    : typeof Promise !== 'undefined'
    ? callback =>
        Promise.resolve(null)
          .then(callback)
          .catch(handleErrorInNextTick)
    : scheduleTimeout; // TODO: Determine the best fallback here.

function handleErrorInNextTick(error) {
  setTimeout(() => {
    throw error;
  });
}

export const supportsMutation = true;
export const supportsHydration = true;
export const supportsTestSelectors = true;

然后在 /src/react/packages/react-dom/src/client/ReactDOMHostConfig.js 中找到 所有在 util.js 中定义的常量 并删除掉, 最后在末尾导出 util.js

export * from './util';