Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”. This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

As one of the best open source frameworks for the front-end, React is something every front-end developer should learn from. This year, I spent a long time understanding and reading the React source code repeatedly. I feel that I have gained a lot. During the National Day holiday, I plan to write a series of articles about the react V17 source code analysis to discuss and learn with everyone.

By learning the source code, you can improve your ability to troubleshoot bugs in projects, better understand the react process and work mode, improve your ability to design data structures and algorithms, and most importantly, improve your ability to interview.

Series directory

This series of source code analysis of React is v17.0.2. It will start with the introduction of react application. It covers most of the main functions and core of react dependency.

  • JSX and React. The createElement method
  • ReactDOM.render
  • The fiber architecture
  • concurrent mode
  • Render and Commit phases
  • Reconciliation and diff algorithms
  • Hooks source

Because the above chapter is not finished, the actual writing process may be slightly adjusted, this chapter will be updated at any time, interested readers suggest bookkeeping this chapter as a directory navigation.

Install react source code debugging environment

Learn how to read the source code for yourself. If you want to read the source code, you must debug the source code. Here is how to build a debug environment for the React source code.

Create a project

Create a react project using create-react-app.

npx create-react-app debug-react
Copy the code

Expose the WebPack configuration

We want to replace the react package in node_modules with the react source code. We need to modify the webpack, run the following command in the debug-react directory to expose the webpack configuration:

cd ./debug-react
yarn eject
Copy the code

Are you sure you want to eject? This action is permanent. Select y and you can see the webpack configuration file in the newly added config folder after executing the command:

React source code and changes to the Webpack

Because the react package in node_modules is a packaged file, a lot of code is mixed into one file, which makes it difficult to debug the source code. React SRC = debug-react

Git clone https://github.com/facebook/react.git - 17.0.2 bCopy the code

Install the dependency by executing the following command in the SRC /react directory:

yarn install
Copy the code

Then we changed the configuration of webPack so that the NPM packages introduced in the code like React point to the source code instead of node_modules. Add the following package references under config/webpack.config.js:

/ /... module.exports = { // ... 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 || {}),+ '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'),}}},Copy the code

Modifying environment Variables

__DEV__ and other environment variables will be enabled by default for debugging purposes.

// ...
function getClientEnvironment(publicUrl) {
  // ...
  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; }, {})}; return { raw, stringified }; }Copy the code

Create the.eslintrc.json file in the debug-react root directory as follows:

{
  "extends": "react-app"."globals": {
    "__DEV__": true."__PROFILE__": true."__UMD__": true."__EXPERIMENTAL__": true}}Copy the code

Resolve a series of errors

After the environment is configured, yarn Start will cause a series of errors. Some traversals in React are generated according to environment injection during packaging. We need to debug the source code directly. So let’s get straight to the problem solved.

Add the ReactFiberHostConfig reference

The following error

Attempted import error: 'afterActiveInstanceBlur' is not exported from './ReactFiberHostConfig'.
Copy the code

Solution:

Directly modify SRC/react/packages/react – the reconciler/SRC/ReactFiberHostConfig js content is as follows:

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

+ export * from './forks/ReactFiberHostConfig.dom'
Copy the code

In addition to modify SRC/react/packages/Shared/ReactSharedInternals js, directly from the introduction of ReactSharedInternals and export:

- import * as React from 'react';
- const ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;

+ import ReactSharedInternals from '.. /react/src/ReactSharedInternals';
Copy the code

Modify the React reference mode

The following error

Attempted import error: 'react' does not contain a default export (imported actFiberHosts 'React').
Copy the code

Solution:

SRC /index.js react and react-dom import methods:

- import React from 'react';
- import ReactDOM from 'react-dom';
+ import * as React from 'react';
+ import * as ReactDOM from 'react-dom';
Copy the code

Modify inveriant

The following error

Error: Internal React error: invariant() is meant to be replaced at compile time. There is no runtime version.
Copy the code

Solution:

Modify the SRC/react/packages/Shared/invariant. The js content:

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.',
  );
}
Copy the code

Resolve ESLint errors

That leaves a bunch of esLint errors, such as:

Failed to load config "fbjs" to extend from.
Copy the code

Solution:

Eslint error content too much, I here simple and crude will webpack eslint plugin directly to turn off, modify SRC/config/webpack config. Js files:

module.exports = {
  // ...
  plugins: [
    // ...
-! 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',
-}),
-},
-},
-}),]}Copy the code

conclusion

The React source code can be debugger interrupt points or console.log() output logs for fun!

Last but not least, post the github address of the installed debug environment: debug-react. If you don’t want to build your own debug environment, you can clone it directly and use it.