從頭寫一個 React-like 框架:工程搭建

最近在網上看到了 Build your own React 這篇文章,做者從零開始實現了一個簡易類 React 框架,雖然沒有過多的優化,但 React 中的核心思想 Concurrent ModeFiber Reconciler 等都有實現,看完後對理解 React 有很大幫助,所以我想在 Build your own React 的基礎上,對代碼進行拆分,搭建起本身的框架工程,而後完善教程中沒完成的其餘功能,代碼在 rac 中。node

工程搭建

技術棧上我選擇用 TypeScript 開發,Rollup 打包, 都是平時用的很少的技術,順帶一塊兒練練手,並且相比 webpack, rollup 配置更簡單一些。在工程中建立一個 tsconfig.json 和一個 rollup.config.js, 而後安裝一下須要的 rollup 插件,好比 rollup-plugin-typescript2rollup-plugin-terser。另外準備一個 examples 文件夾,建立一個小型的 demo 工程,使用 tsx 開發react

支持 jsx

若是想讓 TypeScript 支持 jsx,須要在 tsconfig 中開啓 jsx TypeScript 自帶了三種模式: preservereact,和 react-native,咱們設置爲 react, TypeScript 就會將代碼中的 jsx 翻譯成 React.createElement,這也是在使用 jsx 時,React 必需要在做用域中的緣由。webpack

可是咱們要本身實現一個 React-like 框架,徹底能夠給 React.createElement 換個名字。在 Build your own React 中,做者經過 /** @jsx Didact.createElement */ 註釋,告訴編譯器將 jsx 的輸出函數改成 Didact.createElement,這個方法只對當前文件生效,若是是在工程中使用爲每一個文件都加一行註釋就麻煩了。咱們經過另外一種辦法,在 tsconfig 中經過 jsxFactory 屬性指定,咱們這裏叫 h,除了 React.createEmenent,還有個特殊元素 - Fragment,TypeScript 默認會翻譯成 React.Fragment,咱們經過 jsxFragmentFactory 直接改成 Fragmentgit

tsconfig.json:es6

{
  "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,再額外加一些插件就能夠了:github

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 一些額外配置:web

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 中,做者依照typescript

  • 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,爲了提升代碼可讀性和可維護性,會把這些功能劃分到不一樣的文件中:json

.
├── 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 這個框架。react-native

相關文章
相關標籤/搜索