minhuaF / blog

I will write my front-end story.
9 stars 1 forks source link

本地搭建react源码调试环境 #13

Open minhuaF opened 3 years ago

minhuaF commented 3 years ago

此文档可用于调试和学习react源码,适用于当前最新版本(17.0.2)

本地调试react源码的步骤

对本地项目的修改

  1. debug-react 包括了步骤1、2、3,可以直接下载使用;

  2. 生成react项目

    npx create-react-app debug-react
  3. 暴露 webpack 配置

    npm run eject

    3.在src目录下下载react(此文章编写时react版本是17.0.2)

    git submodule add https://github.com/facebook/react

    4.在 config/webpack.config.js 中修改 react 的引用

    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'),
         //'react-events': path.resolve(__dirname, '../src/react/packages/events')
    }
    }
  4. 修改react的引用

    
    // import React from 'react';
    // import ReactDOM from 'react-dom';

import as React from "react"; import as ReactDOM from "react-dom";


6. 修改config/env.js
```javascript
const stringified = {
    'process.env': Object.keys(raw).reduce((env, key) => {
      env[key] = JSON.stringify(raw[key]);
      return env;
    }, {}),
    __DEV__: true,
    __PROFILE__: true,
    __UMD__: true,
    __EXPERIMENTAL__: true,
};

修改 react

  1. /src/react/packages/react-reconciler/src/ReactFiberHostConfig.js
    // import invariant from 'shared/invariant';
    //invariant(false, 'This module must be shimmed by a specific renderer.'); //sy
    export * from './forks/ReactFiberHostConfig.dom';
  2. /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."
    );
    }
  3. /src/react/packages/shared/ReactSharedInternals.js
    
    // import React from 'react';
    // const ReactSharedInternals =
    //   React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;

import ReactSharedInternals from '../react/src/ReactSharedInternals';


4. /src/react/packages/scheduler/index.js
```javascript
"use strict";

export * from "./src/Scheduler";
// 添加以下内容
export {
  unstable_flushAllWithoutAsserting,
  unstable_flushNumberOfYields,
  unstable_flushExpired,
  unstable_clearYields,
  unstable_flushUntilNextPaint,
  unstable_flushAll,
  unstable_yieldValue,
  unstable_advanceTime,
} from "./src/SchedulerHostConfig.js";
  1. react/.eslintrc.js

    • extends: []
    • no-function-declare-after-returnreact-internal 相关配置屏蔽,并搜索 /src/react/packages/,把相关的注释都删除。
  2. react/packages/react-dom/src/client下创建CONST.js文件,内容如下(主要解决循环引用问题)

/**

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;


7. 在`react/packages/react-dom/src/client/ReactDOMHostConfig.js` 中找到`CONST.js`文件中定义的变量并注释,在`ReactDOMHostConfig.js`文件最后添加`export * from './CONST.js'`

8. 启动项目`npm start`, 控制台显示success,但是打开页面会有error,直接在`/src/react`项目下搜索并删除即可,有点多,建议批量操作
```javascript
src/react/packages/react-dom/src/client/ReactDOM.js
  Line 238:9:  Definition for rule 'react-internal/no-production-logging' was not found  react-internal/no-production-logging

src/react/packages/react-reconciler/src/ReactFiberHooks.new.js
  Line 1014:7:  Definition for rule 'react-internal/no-production-logging' was not found  react-internal/no-production-logging

src/react/packages/react-reconciler/src/ReactFiberHooks.old.js
  Line 1014:7:  Definition for rule 'react-internal/no-production-logging' was not found  react-internal/no-production-logging

src/react/packages/react-reconciler/src/ReactFiberHostConfig.js
  Line 10:1:   Definition for rule 'react-internal/invariant-args' was not found  react-internal/invariant-args
  Line 23:15:  Strings must use singlequote                                       quotes

src/react/packages/react-reconciler/src/ReactFiberWorkLoop.new.js
  Line 3201:7:  Definition for rule 'react-internal/no-production-logging' was not found  react-internal/no-production-logging

src/react/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
  Line 3201:7:  Definition for rule 'react-internal/no-production-logging' was not found  react-internal/no-production-logging

src/react/packages/shared/ConsolePatchingDev.js
  Line 30:7:  Definition for rule 'react-internal/no-production-logging' was not found  react-internal/no-production-logging
  Line 55:7:  Definition for rule 'react-internal/no-production-logging' was not found  react-internal/no-production-logging
  Line 65:7:  Definition for rule 'react-internal/no-production-logging' was not found  react-internal/no-production-logging
  Line 81:7:  Definition for rule 'react-internal/no-production-logging' was not found  react-internal/no-production-logging

src/react/packages/shared/ReactSharedInternals.js
  Line 14:36:  Strings must use singlequote  quotes

Search for the keywords to learn more about each error.

在react源码中添加第一个debugger

在 src\react\packages\react\src\ReactBaseClasses.js 的Component中打个debugger,刷新页面即可看到断点进去了。

/**
 * Base class helpers for the updating state of a component.
 */
function Component(props, context, updater) {
  debugger
  this.props = props;
  this.context = context;
  // If a component has string refs, we will assign a different object later.
  this.refs = emptyObject;
  // We initialize the default updater but the real one gets injected by the
  // renderer.
  this.updater = updater || ReactNoopUpdateQueue;
}

参考资料