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.