本地搭建react源码调试环境
minhuaF opened this issue · comments
此文档可用于调试和学习react
源码,适用于当前最新版本(17.0.2)
本地调试react
源码的步骤
对本地项目的修改
-
debug-react 包括了步骤1、2、3,可以直接下载使用;
-
生成
react
项目
npx create-react-app debug-react
- 暴露
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')
}
}
- 修改
react
的引用
// import React from 'react';
// import ReactDOM from 'react-dom';
import * as React from "react";
import * as ReactDOM from "react-dom";
- 修改config/env.js
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
包
- /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';
- /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/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';
- /src/react/packages/scheduler/index.js
"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";
- react/.eslintrc.js
- extends: []
- 把
no-function-declare-after-return
和react-internal
相关配置屏蔽,并搜索/src/react/packages/
,把相关的注释都删除。
- 在
react/packages/react-dom/src/client
下创建CONST.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;
-
在
react/packages/react-dom/src/client/ReactDOMHostConfig.js
中找到CONST.js
文件中定义的变量并注释,在ReactDOMHostConfig.js
文件最后添加export * from './CONST.js'
-
启动项目
npm start
, 控制台显示success,但是打开页面会有error,直接在/src/react
项目下搜索并删除即可,有点多,建议批量操作
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;
}