從頭寫React-like框架的工程搭建實(shí)現(xiàn)
最近在網(wǎng)上看到了 Build your own React 這篇文章,作者從零開始實(shí)現(xiàn)了一個(gè)簡(jiǎn)易類 React 框架,雖然沒有過多的優(yōu)化,但 React 中的核心思想 Concurrent Mode,F(xiàn)iber Reconciler 等都有實(shí)現(xiàn),看完后對(duì)理解 React 有很大幫助,因此我想在 Build your own React 的基礎(chǔ)上,對(duì)代碼進(jìn)行拆分,搭建起自己的框架工程,然后完善教程中沒完成的其他功能,代碼在 rac 中。
工程搭建
技術(shù)棧上我選擇用 TypeScript 開發(fā),Rollup 打包, 都是平時(shí)用的不多的技術(shù),順帶一起練練手,而且相比 webpack, rollup 配置更簡(jiǎn)單一些。在工程中創(chuàng)建一個(gè) tsconfig.json 和一個(gè) rollup.config.js, 然后安裝一下需要的 rollup 插件,比如 rollup-plugin-typescript2, rollup-plugin-terser。另外準(zhǔn)備一個(gè) examples 文件夾,創(chuàng)建一個(gè)小型的 demo 工程,使用 tsx 開發(fā)
支持 jsx
如果想讓 TypeScript 支持 jsx,需要在 tsconfig 中開啟 jsx TypeScript 自帶了三種模式: preserve, react,和 react-native,我們?cè)O(shè)置為 react, TypeScript 就會(huì)將代碼中的 jsx 翻譯成 React.createElement,這也是在使用 jsx 時(shí),React 必須要在作用域中的原因。
但是我們要自己實(shí)現(xiàn)一個(gè) React-like 框架,完全可以給 React.createElement 換個(gè)名字。在 Build your own React 中,作者通過 /** @jsx Didact.createElement */ 注釋,告訴編譯器將 jsx 的輸出函數(shù)改為 Didact.createElement,這個(gè)方法只對(duì)當(dāng)前文件生效,如果是在工程中使用為每個(gè)文件都加一行注釋就麻煩了。我們通過另一種辦法,在 tsconfig 中通過 jsxFactory 屬性指定,我們這里叫 h,除了 React.createEmenent,還有個(gè)特殊元素 - Fragment,TypeScript 默認(rèn)會(huì)翻譯成 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 的配置比較簡(jiǎn)單,除了 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: { ... } }
項(xiàng)目結(jié)構(gòu)
React 新的 Fiber 架構(gòu)有幾個(gè)核心概念,在 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
這幾步逐步實(shí)現(xiàn)了一個(gè) mini React,為了提高代碼可讀性和可維護(hù)性,會(huì)把這些功能劃分到不同的文件中:
. ├── 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 相關(guān)工作
- h.ts 中是對(duì) jsxFactory, jsxFragmentFactory 的實(shí)現(xiàn)
- hooks.ts 中是對(duì) hooks 的實(shí)現(xiàn)
- reconciler.ts 是 reconcile 階段和 commit 階段的實(shí)現(xiàn)
- shceduler.ts 是任務(wù)調(diào)度器的實(shí)現(xiàn)
- type.ts 是一些類型定義
到這工程就搭建起來了,整個(gè)工程的結(jié)構(gòu)和一些代碼實(shí)現(xiàn)上借鑒了 fre 這個(gè)框架。
到此這篇關(guān)于從頭寫React-like框架的工程搭建實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)React-like搭建內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react中的forwardRef 和memo的區(qū)別解析
forwardRef和memo是React中用于性能優(yōu)化和組件復(fù)用的兩個(gè)高階函數(shù),本文給大家介紹react中的forwardRef 和memo的區(qū)別及適用場(chǎng)景,感興趣的朋友跟隨小編一起看看吧2023-10-10React實(shí)現(xiàn)控制減少useContext導(dǎo)致非必要的渲染詳解
這篇文章主要介紹了React如何有效減少使用useContext導(dǎo)致的不必要渲染,使用useContext在改變一個(gè)數(shù)據(jù)時(shí),是通過自己逐級(jí)查找對(duì)比改變的數(shù)據(jù)然后渲染,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11React利用插件和不用插件實(shí)現(xiàn)雙向綁定的方法詳解
我們知道在 angular 中數(shù)據(jù)時(shí)雙向綁定的;而在 react 中,數(shù)據(jù)是向一個(gè)方向傳遞:從擁有者到子節(jié)點(diǎn)。也就是我們說的單向數(shù)據(jù)綁定。那如何實(shí)現(xiàn)雙向綁定呢?下面這篇文章主要給大家介紹了關(guān)于React利用插件和不用插件實(shí)現(xiàn)雙向綁定的方法,需要的朋友可以參考下。2017-07-07react學(xué)習(xí)每天一個(gè)hooks?useWhyDidYouUpdate
這篇文章主要為大家介紹了react學(xué)習(xí)每天一個(gè)hooks?useWhyDidYouUpdate使用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04Zustand介紹與使用 React狀態(tài)管理工具的解決方案
本文主要介紹了Zustand,一種基于React的狀態(tài)管理庫,Zustand以簡(jiǎn)潔易用、靈活性高及最小化原則等特點(diǎn)脫穎而出,旨在提供簡(jiǎn)單而強(qiáng)大的狀態(tài)管理功能2024-10-10解決React報(bào)錯(cuò)Unexpected default export of an
這篇文章主要為大家介紹了React報(bào)錯(cuò)Unexpected default export of anonymous function解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12一文教你如何避免React中常見的8個(gè)錯(cuò)誤
這篇文章主要來和大家一起分享在?React?開發(fā)中常見的一些錯(cuò)誤,以及如何避免這些錯(cuò)誤,理解這些問題背后的細(xì)節(jié),防止犯下類似的錯(cuò)誤,需要的可以參考下2023-12-12ReactNative頁面跳轉(zhuǎn)實(shí)例代碼
這篇文章主要介紹了ReactNative頁面跳轉(zhuǎn)的代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09