深入理解 React 源码,带你从零实现 React v18 的核心功能,构建自己的 React 库。
React 是由卓越工程师们在数年时间内精心打造的库,其中必定蕴含了许多值得借鉴的经验和智慧。
如果你渴望更进一步,不仅仅停留在 API 的使用层面,而是追求更深入前端技术的探索,那么掌握 React 源码将成为你技能提升的极佳途径。
本系列文章遵循 React 源码的核心思想,通俗易懂的解析 React 源码,带你从零实现 React v18 的核心功能,学完本系列,你将有这些收获:
- 面试加分:框架底层原理是面试必问环节,熟悉 React 源码会为你的面试加分,也会为你拿下 offer 增加不少筹码;
- 提升开发效率:熟悉 React 源码之后,会对 React 的运行流程有新的认识,让你在日常的开发中,对性能优化、使用技巧和 bug 解决更加得心应手;
- 巩固基础知识:学习本书也顺便巩固了数据结构和算法,如 reconciler 中使用了 fiber、update、链表等数据结构,diff 算法要考虑怎样降低对比复杂度;
本系列文章的特色:
- 教程详细,代码开源,带你构建自己的 React 库;
- 功能全面,可跑通官方测试用例;
- 按 Git Tag 划分迭代步骤,记录每个功能的实现过程;
1. 选择项目结构
选择 Multi-repo 还是 Mono-repo?
- Multi-repo 每个库都有独立的仓库,逻辑清晰,但协同管理会更繁琐;
- Mono-repo 可以方便的协同管理不同独立的库的生命周期,但是会有更高的操作复杂度。
很多大型项目都使用 Mono-repo 结构管理,比如 Vue,Bable,我们也选择 Mono-repo。
2. 选择 Mono-repo 工具
简单工具:
- npm workspace
- Yarn workspace
- pnpm workspace
专业工具:
- nx
- bit
- turborepo
- rush
- nx
- lerna
我们选择 pnpm
,因为它相比其它打包工具,依赖安装更快,更规范(处理幽灵依赖问题)。
安装 pnpm
npm install -g pnpm
初始化pnpm
pnpm init
在根目录新增 pnpm-workspace.yaml
文件,并初始化,写入下面的代码:
// pnpm-workspace.yaml
packages:
- 'packages/*'
pnpm-workspace.yaml
文件定义了工作空间的根目录,也就是说,packages 目录下的文件就是 Mono-repo 的子项目。
3. 配置代码规范
代码规范检查与修复,使用 eslint
。
安装:
pnpm i eslint -D -w
新增.gitignore
文件,忽略node_modules
目录下的文件:
node_modules/*
初始化 eslint:
npx eslint --init
选项选择如下:
√ How would you like to use ESLint?
· To check syntax and find problems
√ What type of modules does your project use?
· JavaScript modules (import/export)
√ Which framework does your project use?
· none
√ Does your project use TypeScript?
· Yes
√ Where does your code run?
· node
√ What format do you want your config file to be in?
· JSON
√ Would you like to install them now?
· Yes
√ Which package manager do you want to use?
· pnpm
如果报错,再执行下面的代码,手动安装这两个包和 typescript:
pnpm i -D -w @typescript-eslint/eslint-plugin, @typescript-eslint/parser, typescript
此时,自动生成了一个.eslintrc.json
文件,它是对 eslint 的一些配置,将.eslintrc.json
文件配置如下:
// .eslintrc.json
{
"env": {
"browser": true,
"es2021": true,
"node": true,
"jest": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"prettier/prettier": "error",
"no-case-declarations": "off",
"no-constant-condition": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-var-requires": "off",
"no-unused-vars": "off"
}
}
安装 ts 的eslint
插件:
pnpm i @typescript-eslint/eslint-plugin -D -w
安装代码风格检查 prettier
:
pnpm i prettier -D -w
新建.prettierrc.json
配置文件,添加配置:
// .prettierrc.json
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": true,
"singleQuote": true,
"semi": true,
"trailingComma": "none",
"bracketSpacing": true
}
将prettier
集成到eslint
中,避免它和eslint
冲突,其中:
eslint-config-prettier
:覆盖eslint
本身的规则配置eslint-plugin-prettier
:用prettier
来接管修复代码,即eslint --fix
pnpm i eslint-config-prettier eslint-plugin-prettier -D -w
在 package.json
的 "scripts"
中增加 lint 对应的执行脚本:
"lint": "eslint --ext .ts,.jsx,.tsx --fix --quiet ./packages"
4. 配置 commit 规范检查
安装husky
,用于拦截 commit 命令:
pnpm i husky -D -w
初始化huaky
:
npx husky install
将刚才实现的格式化命令pnpm lint
纳入 commit 时husky
将执行的脚本:
npx husky add .husky/pre-commit "pnpm lint"
使用commitlint
堆 git 提交信息进行检查:
pnpm i commitlint @commitlint/cli @commitlint/config-conventional -D -w
新建配置文件.commitlintrc.js
,指定规范集:
// .commitlintrc.js
module.exports = {
extends: ['@commitlint/config-conventional']
};
把commitlint
集成到husky
中:
npx husky add .husky/commit-msg "npx --no-install commitlint -e $HUSKY_GIT_PARAMS"
这样之后所有的 commit 都必须符合规范集的格式:提交的类型: 摘要信息,即<type>: <subject>
,例如:git commit -m "feat: project init"
常见的 type 值如下:
feat
: 新功能fix
: 修复docs
: 文档变更style
: 代码格式refactor
: 重构perf
: 性能优化test
: 增加测试revert
: 回退build
: 打包chore
: 构建过程或辅助工具的变动
5. 配置 typescript
新建配置文件tsconfig.json
,并添加以下配置:
// tsconfig.json
{
"compileOnSave": true,
"include": ["./packages/**/*"],
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ESNext", "DOM"],
"moduleResolution": "Node",
"strict": true,
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"noEmit": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitReturns": false,
"skipLibCheck": true,
"baseUrl": "./packages",
"paths": {
"hostConfig": ["./react-reconciler/src/hostConfig.ts"]
}
}
}
6. 选择打包工具
有一个比较权威的网站https://bundlers.tooling.report/,比较了不同的打包工具的区别。
可以看到webpack
是比较大而全的,但是我们要开发的是一个库,而不是业务代码,希望工具尽可能简洁,打包产物可读性高,所以选择rollup
。
安装rollup
:
pnpm i rollup -D -w
新建文件夹scripts/rollup
,用于放所有的打包脚本。
至此,我们的项目框架就搭建完成了。
相关代码可在 git tag v1.1
查看,地址:https://github.com/2xiao/my-react/tree/v1.1
版权声明:本系列文章是基于 《从 0 实现 React18》 整理创作的,视频教程的作者是 @卡颂 。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。