Shane Jix

搭建 React 17 源码本地调试环境

create:April 11, 2022  update:April 12, 2022  ☕️ 5 min read

同步链接: https://www.shanejix.com/posts/搭建 React 17 源码本地调试环境/

通过这种方式只能调试编译之后的代码,不能实现原汁原味的源代码调试体验。查阅一些社区的实现,记录下步骤,方便后续查阅。

也可以直接 clone 配置好的仓库:https://github.com/shanejix/react-source-code-debug

步骤

  1. 使用 create-react-app 脚手架创建项目
npx create-react-app react-source-code-debug
  1. 弹射 create-react-app 脚手架内部配置
yarn run eject
  1. 克隆 react 官方源码 (在项目的根目录下进行克隆)
git clone --branch v17.0.2 --depth=1 https://github.com/facebook/react.git src/react
  1. 通过 alias ,链接本地源码
// 文件位置: react-source-code-debug/config/webpack.config.js

resolve: {
  // ...
  alias: {
    // Support React Native Web
    // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
    'react-native': 'react-native-web',
    // Allows for better profiling with ReactDevTools
    ...(isEnvProductionProfile && {
      'react-dom$': 'react-dom/profiling',
      'scheduler/tracing': 'scheduler/tracing-profiling',
    }),
    ...(modules.webpackAliases || {}),
    + // FIXME: REACT SOURCE CODE DEBUG
    + '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'),
    + // 'scheduler': path.resolve(__dirname, '../src/react/packages/scheduler'),
  },
}
  1. 修改环境变量
// 文件位置: react-source-code-debug/config/env.js

// FIXME: REACT SOURCE CODE DEBUG
const stringified = {
  + __DEV__: true,
  + __PROFILE__: true,
  + __UMD__: true,
  + __EXPERIMENTAL__: true,
  'process.env': Object.keys(raw).reduce((env, key) => {
    env[key] = JSON.stringify(raw[key]);
    return env;
  }, {}),
};
  1. 在根目录创建 eslintrc.json文件,内容如下
{
  "extends": "react-app",
  "globals": {
    "__DEV__": true,
    "__PROFILE__": true,
    "__UMD__": true,
    "__EXPERIMENTAL__": true
  }
}
  1. 修改 ReactFiberHostConfig.js 文件
// 文件位置: /react/packages/react-reconciler/src/ReactFiberHostConfig.js

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

+ // FIXME: REACT SOURCE CODE DEBUG
+ export * from './forks/ReactFiberHostConfig.dom'
  1. 修改 ReactSharedInternals.js 文件
// 文件位置: /react/packages/shared/ReactSharedInternals.js

- import * as React from 'react';

- const ReactSharedInternals =
-   React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;

+ // FIXME: REACT SOURCE CODE DEBUG
+ import ReactSharedInternals from '../react/src/ReactSharedInternals';

+ export default ReactSharedInternals;
  1. 修改 invariant.js 文件
// 文件位置: /react/packages/shared/invariant.js

export default function invariant(condition, format, a, b, c, d, e, f) {

  + // FIXME: REACT SOURCE CODE DEBUG
  + if (condition) {
  +   return;
  + }

  throw new Error(
    'Internal React error: invariant() is meant to be replaced at compile ' +
    'time. There is no runtime version.',
  );
}
  1. 新增 Scheduler导出
// 文件位置:src/react/packages/scheduler/src/Scheduler.js


+ // FIXME: REACT SOURCE CODE DEBUG
+ export {
+   unstable_flushAllWithoutAsserting,
+   unstable_flushNumberOfYields,
+   unstable_flushExpired,
+   unstable_clearYields,
+   unstable_flushUntilNextPaint,
+   unstable_flushAll,
+   unstable_yieldValue,
+   unstable_advanceTime
+ } from './forks/SchedulerHostConfig.mock.js';
+
+ export {
+   requestHostCallback,
+   requestHostTimeout,
+   cancelHostTimeout,
+   shouldYieldToHost,
+   getCurrentTime,
+   forceFrameRate,
+   requestPaint
+ } from './forks/SchedulerHostConfig.default.js';
  1. 关闭 eslint 扩展
// 文件位置: react/.eslingrc.js [module.exports]

- extends: [
-  'fbjs',
-  'prettier'
- ]
  1. 解决 eslint 报错
// 将 webpack 中 eslint 插件给关掉,修改 src/config/webpack.config.js 文件

// ...

// FIXME: REACT SOURCE CODE DEBUG

// !disableESLintPlugin &&
// new ESLintPlugin({
//   // Plugin options
//   extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
//   formatter: require.resolve('react-dev-utils/eslintFormatter'),
//   eslintPath: require.resolve('eslint'),
//   failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
//   context: paths.appSrc,
//   cache: true,
//   cacheLocation: path.resolve(
//     paths.appNodeModules,
//     '.cache/.eslintcache'
//   ),
//   // ESLint class options
//   cwd: paths.appPath,
//   resolvePluginsRelativeTo: __dirname,
//   baseConfig: {
//     extends: [require.resolve('eslint-config-react-app/base')],
//     rules: {
//       ...(!hasJsxRuntime && {
//         'react/react-in-jsx-scope': 'error',
//       }),
//     },
//   },
// }),
  1. 告诉 babel 在转换代码时忽略类型检查
yarn add @babel/plugin-transform-flow-strip-types -D
// 文件位置: react-source-code-debug/config/webpack.config.js [babel-loader]

plugins: [
  // ...

  // FIXME: REACT SOURCE CODE DEBUG
  [require.resolve("@babel/plugin-transform-flow-strip-types")],
];
  1. 新增 eslint 配置
// 在 react 源码文件夹中新建 .eslintrc.json 并添加如下配置

{
  "extends": "react-app",
  "globals": {
    "__DEV__": true,
    "__PROFILE__": true,
    "__UMD__": true,
    "__EXPERIMENTAL__": true
  }
}
  1. 修改 react react-dom 引入方式
- // import React from 'react';
- // import ReactDOM from 'react-dom';

+ // FIXME: REACT SOURCE CODE DEBUG

+ import * as React from 'react';
+ import * as ReactDOM from 'react-dom';
  1. 解决 VSCode 中 flow 报错
// 新建 .vscode/setting.js

{
  "typescript.validate.enable": false,
  "javascript.validate.enable": false
}
  1. 解决 DEV 报错
// 删除 node_modules 文件夹,执行 npm install / yarn

// 根目录下

rm -fr node_modules && yarn

references

作者:shanejix 出处:https://www.shanejix.com/posts/搭建 React 17 源码本地调试环境/ 版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。 声明:转载请注明出处!

Edit on GitHubDiscuss on GitHub


Shane Jix

Personal blog by Shane Jix. I explain with words and code.

LinksTools
© 2019 - 2022, Built withGatsby