乐趣区

关于react.js:从头写一个-Reactlike-框架工程搭建

最近在网上看到了 Build your own React 这篇文章,作者从零开始实现了一个繁难类 React 框架,尽管没有过多的优化,但 React 中的核心思想 Concurrent ModeFiber Reconciler 等都有实现,看完后对了解 React 有很大帮忙,因而我想在 Build your own React 的根底上,对代码进行拆分,搭建起本人的框架工程,而后欠缺教程中没实现的其余性能,代码在 rac 中。

工程搭建

技术栈上我抉择用 TypeScript 开发,Rollup 打包, 都是平时用的不多的技术,顺带一起练练手,而且相比 webpack,rollup 配置更简略一些。在工程中创立一个 tsconfig.json 和一个 rollup.config.js, 而后装置一下须要的 rollup 插件,比方 rollup-plugin-typescript2rollup-plugin-terser。另外筹备一个 examples 文件夹,创立一个小型的 demo 工程,应用 tsx 开发

反对 jsx

如果想让 TypeScript 反对 jsx,须要在 tsconfig 中开启 jsx TypeScript 自带了三种模式:preservereact,和 react-native,咱们设置为 react,TypeScript 就会将代码中的 jsx 翻译成 React.createElement,这也是在应用 jsx 时,React 必须要在作用域中的起因。

然而咱们要本人实现一个 React-like 框架,齐全能够给 React.createElement 换个名字。在 Build your own React 中,作者通过 /** @jsx Didact.createElement */ 正文,通知编译器将 jsx 的输入函数改为 Didact.createElement,这个办法只对以后文件失效,如果是在工程中应用为每个文件都加一行正文就麻烦了。咱们通过另一种方法,在 tsconfig 中通过 jsxFactory 属性指定,咱们这里叫 h,除了 React.createEmenent,还有个非凡元素 – Fragment,TypeScript 默认会翻译成 React.Fragment,咱们通过 jsxFragmentFactory 间接改为 Fragment

tsconfig.json:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "moduleResolution": "node",
    "jsx": "react", // enable jsx
    "jsxFactory": "h", // React.createElement => h
    "jsxFragmentFactory": "Fragment", // React.Fragment => Fragment
    "rootDir": "./src",
    "lib": ["dom", "es2015"]
  }
}

Rollup 配置

Rollup 的配置比较简单,除了 input,output,再额定加一些插件就能够了:

const path = require('path')
const typescript = require('rollup-plugin-typescript2')
const {terser} = require('rollup-plugin-terser')
const eslint = require('@rollup/plugin-eslint')

export default {
  input: 'src/index.ts',
  output: [{ file: 'dist/rac.umd.js', format: 'umd', name: 'rac'}
  ],
  plugins: [terser(),
    eslint({
      throwOnError: true,
      include: ['src/**/*.ts']
    }),
    typescript({
      verbosity: 0,
      tsconfig: path.resolve(__dirname, 'tsconfig.json'),
      useTsconfigDeclarationDir: true
    })
  ]
}

Eslint in TypeScript

为了能让 Eslint 反对 TypeScript,须要给 Eslint 一些额定配置:

module.exports = {
  parser: '@typescript-eslint/parser',
  env: {
    es6: true,
    browser: true
  },
  plugins: ['@typescript-eslint'],
  extends: ['eslint:recommended',],
  parserOptions: {sourceType: 'module'},
  rules: {...}
}

我的项目构造
React 新的 Fiber 架构有几个外围概念,在 Build your own React 中,作者按照

  • Step I: The createElement Function
  • Step II: The render Function
  • Step III: Concurrent Mode
  • Step IV: Fibers
  • Step V: Render and Commit Phases
  • Step VI: Reconciliation
  • Step VII: Function Components
  • Step VIII: Hooks

这几步逐渐实现了一个 mini React,为了进步代码可读性和可维护性,会把这些性能划分到不同的文件中:

.
├── README.md
├── examples  // demo 目录
├── package.json
├── rollup.config.js
├── src
│   ├── dom.ts
│   ├── h.ts
│   ├── hooks.ts
│   ├── index.ts
│   ├── reconciler.ts
│   ├── scheduler.ts
│   └── type.ts
└── tsconfig.json
  • dom.ts 中解决 DOM 相干工作
  • h.ts 中是对 jsxFactory, jsxFragmentFactory 的实现
  • hooks.ts 中是对 hooks 的实现
  • reconciler.ts 是 reconcile 阶段和 commit 阶段的实现
  • shceduler.ts 是任务调度器的实现
  • type.ts 是一些类型定义

到这工程就搭建起来了,整个工程的构造和一些代码实现上借鉴了 fre 这个框架。

退出移动版