【从0实现React18】 (二) JSX 的转换 jsx到底是什么?React是如何把jsx转换为ReactElement?

react项目结构

  • React(宿主环境的公用方法)
  • React-reconciler(协调器的实现,宿主环境无关)
  • 各种宿主环境的包
  • shared(公用辅助方法,宿主环境无关)

当前实现的JSX转换属于 react****包

初始化react包

先创建react package并初始化

更新package.json文件:

{"name": "react","version": "1.0.0","description": "react公用方法","module": "index.ts","keywords": [],"author": "","license": "ISC"
}

JSX转换是什么

jsx在线转换

包括两部分

  • 编译时
  • 运行时:jsx方法或react.createElement方法的实现(包括dev、prod两个环境)

实现运行时 jsx 转换

编译时由babel编译实现,我们实现运行时,工作量包括:

  • 实现jsx方法
  • 实现打包流程
  • 实现调试打包结果的环境
  1. 实现jsx方法

包括:

  • jsxDEV方法(dev环境)
  • jsx方法(prod环境)
  • React.craeteElement方法

实现:react/src/jsx.ts:

import { REACT_ELEMENT_TYPE } from '@/shared/ReactSymbols'
import {Type,Key,Ref,Props,ElementType,ReactElementType,
} from '@/shared/ReactTypes'// ReactElement 构造函数实现
const ReactElement = function (type: Type,key: Key,ref: Ref,props: Props
): ReactElementType {const element = {$$typeof: REACT_ELEMENT_TYPE, // 内部字段, 指明当前字段是reactElementtype,key,ref,props,__mark: 'khs', // 该字段是为了与真实的react项目区分开}return element
}// jsx 函数实现
export const jsx = (type: ElementType, config: any, ...maybeChildren: any) => {let key: Key = nulllet ref: Ref = nullconst props: Props = {}// 遍历configfor (const prop in config) {const val = config[prop]// 1. 单独找出 key和ref字段if (prop === 'key') {if (val !== undefined) {key = '' + val}continue}if (prop === 'ref') {if (val !== undefined) {ref = val}continue}// 2. 剩下的如果是config自身的prop, 则正常取出if ({}.hasOwnProperty.call(config, prop)) {props[prop] = val}}const maybeChildrenLength = maybeChildren.lengthif (maybeChildrenLength) {// [child] 或 [child, child, child]if (maybeChildrenLength === 1) {props.child = maybeChildren[0]} else {props.child = maybeChildren}}return ReactElement(type, key, ref, props)
}// jsxDEV 函数实现
export const jsxDEV = (type: ElementType, config: any) => {let key: Key = nulllet ref: Ref = nullconst props: Props = {}// 遍历configfor (const prop in config) {const val = config[prop]// 1. 单独找出 key和ref字段if (prop === 'key') {if (val !== undefined) {key = '' + val}continue}if (prop === 'ref') {if (val !== undefined) {ref = val}continue}// 2. 剩下的如果是config自身的prop, 则正常取出if ({}.hasOwnProperty.call(config, prop)) {props[prop] = val}}return ReactElement(type, key, ref, props)
}

react/index.tsx:

/*** 打包出的React包*/import { jsxDEV } from './src/jsx'
export default {version: '0.0.0',createElement: jsxDEV,
}

同时因为react引入了shared包,所以为react/package.json添加依赖:

{"name": "react","version": "1.0.0","description": "react公用方法","module": "index.ts","dependencies": {"shared": "workspace: *"  },"keywords": [],"author": "","license": "ISC"
}
  1. 实现打包流程

对应上述3方法,打包对应文件

  • react/jsx-dev-runtime.js(dev环境)
  • react/jsx-runtime.js(prod环境)
  • react

1、安装rollup Plugin

  • 兼容commonjs: @rollup/plugin-commonjs
  • ts解析为js: rollup-plugin-typescript2
  • 生成package.json文件:rollup-plugin-generate-package-json
pnpm i -D -w rollup-plugin-typescript2pnpm i -D -w @rollup/plugin-commonjspnpm i -D -w rollup-plugin-generate-package-json
  1. react包rollup打包配置:

scripts/rollup/react.config.js:

import { getBaseRollupPlugins, getPackageJSON, resolvePkgPath } from './utils'import generatePackageJson from 'rollup-plugin-generate-package-json'const { name, module } = getPackageJSON('react')
// react包的路径
const pkgPath = resolvePkgPath(name)
//react产物路径
const pkgDistPath = resolvePkgPath(name, true)export default [// react 的包{input: `${pkgPath}/${module}`,output: {file: `${pkgDistPath}/index.js`,name: 'index.js',format: 'umd', // 该格式能够兼容commonjs},plugins: [...getBaseRollupPlugins(),// 生成package.json文件generatePackageJson({inputFolder: pkgPath,outputFolder: pkgDistPath,baseContents: ({ name, description, version }) => ({name,description,version,main: 'index.js',}),}),],},// jsx-runtime 和 jsx-dev-runtime 的包{input: `${pkgPath}/src/jsx.ts`,output: [// jsx-runtime{file: `${pkgDistPath}/jsx-runtime.js`,name: 'jsx-runtime',format: 'umd',},// jsx-dev-runtime{file: `${pkgDistPath}/jsx-dev-runtime.js`,name: 'jsx-dev-runtime.js',format: 'umd',},],plugins: getBaseRollupPlugins(),},
]
  1. 测试打包

安装清除上次打包的文件工具:rimraf

pnpm i -D -w rimraf

添加脚本:

"build:dev": "rimraf dist && rollup --bundleConfigAsCjs --config scripts/rollup/react.config.js"

运行脚本

pnpm build:dev

打包结果:

  1. 调试打包结果

Pnpm link

npm link是一种把包链接到包文件夹的方式,即:可以在不发布npm模块的情况下,调试该模块,并且修改模块后会实时生效,不需要通过npm install进行安装

  • 优点:可以模拟实际项目引用React的清空
  • 缺点:略显繁琐,达不到热更新的效果

先去到模块目录,把它 link 到全局:

cd .\dist\node_modules\react\pnpm link --global

在外部新建一个react项目,然后将我们实现的react link到该项目

npx create-react-app react-demo cd ./react-demopnpm link react --global

修改react-demo/index.js:

import React from 'react'const jsx = (<div key={123} ref={'khs'}>hello<span>big-react</span></div>
)console.log(React)
console.log(jsx)

控制台打印调试后的结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/32432.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务——重复消费(幂等解决方案)

目录 一、唯一ID机制二、幂等性设计三、状态检查机制四、利用缓存和消息队列五、分布式锁总结 在微服务中&#xff0c;防止重复消费的核心思想是通过设计使得操作一次与多次产生相同的效果&#xff0c;并为每次操作生成唯一的ID。这样&#xff0c;即使在消息被重复发送的情况下…

K8S - 实现statefulset 有状态service的灰度发布

什么是灰度发布 Canary Release 参考 理解 什么是 滚动更新&#xff0c;蓝绿部署&#xff0c;灰度发布 以及它们的区别 配置partition in updateStrategy/rollingUpdate 这次我为修改了 statefulset 的1个yaml file statefulsets/stateful-nginx-without-pvc.yaml: --- apiVe…

Android - 跳转到应用商店进行应用打分功能实现

2.将过滤出的这些应用商店展示给用户&#xff0c;如果没有安装任何相关应用商店则提示用户“暂无安装相关应用商店”。 3.用户点击了某应用商店之后&#xff0c;则跳转到该应用商店的APP详情页。 4.下面列出了比较核心的代码&#xff0c;可进行参考。 /** 过滤出已经安装的包…

不同交换机之间相同VLAN间主机通信

1、搭建网络拓扑 搭建拓扑&#xff0c;分配IP地址&#xff0c;划分vlan&#xff0c;分配端口 2、配置交换机 //进入全局配置模式 Switch>enable Switch#config terminal Enter configuration commands, one per line. End with CNTL/Z. Switch(config)#hostname SW1 …

ubuntu 20.04 访问csdn报错 Secure connection failed

打扰了&#xff0c;csdn服务器的问题&#xff0c;和源没关系&#xff0c;后面又重新测试了一下。刚好那一刻网站连上了。 暂时没有好办法&#xff0c;等待一段时间就连上了&#xff0c;改host似乎也不太行。 问题原因&#xff1a; 我一边更新源 sudo apt update & apt up…

OPENCV中0x00007FFE5F35F39C发生异常

原因&#xff1a;读取图片时已经为灰度图像&#xff0c;又进行了一次灰度处理cvtColor 解决方法&#xff1a;如上图所示&#xff0c;将cv::imread的第二个参数改为cv::IMREAD_COLOR&#xff1b;或者保留cv::IMREAD_GRAYSCALE&#xff0c;删去后面的cv::cvtColor

Sequelize入门及简单的增删改查

前言 学习一下NodeJS怎么使用Sequelize怎么查询数据库数据 一、Sequelize是什么&#xff1f; Sequelize 是一个基于 promise 的 Node.js ORM, 二、搭建项目 1.安装过程 npm i -g sequelize-cli //全局安装sequelize-clinpm i sequelize mysql2 //安装sequelize和mysql2…

System.Runtime, Version=6.0.0.0,生成的dll使用出现错误问题

解决&#xff1a; 1.unity左上角file点击选中build settings 点击player settings &#xff0c;然后在player的window的other settings的configuration更改为 Framerwork 其实这个不换也可以的&#xff0c;我后面调试完&#xff0c;发现这个不是重点&#xff0c;下面第2点才是…

Python15 理解Python迭代器

1.Python中的迭代器 在Python中&#xff0c;迭代器是一种允许程序员遍历一个容器&#xff08;特别是列表、元组、字典等集合类型&#xff09;的对象&#xff0c;而不需要了解容器的内部结构。迭代器提供了一个统一的方法来逐一访问容器中的元素&#xff0c;这种机制称为迭代。…

使用自签名 TLS 将 Dremio 连接到 MinIO

Dremio 是一个开源的分布式分析引擎&#xff0c;为数据探索、转换和协作提供简单的自助服务界面。Dremio 的架构建立在 Apache Arrow&#xff08;一种高性能列式内存格式&#xff09;之上&#xff0c;并利用 Parquet 文件格式实现高效存储。有关 Dremio 的更多信息&#xff0c;…

应用占内存,应用太耗电。不如冻起来!

在安卓系统中&#xff0c;一些不常用的系统组件、进程或顽固应用可能会持续在后台运行&#xff0c;占用宝贵的内存资源&#xff0c;导致手机出现卡顿、续航减少等问题。今天我将向您推荐几款实用的应用冻结工具&#xff0c;它们能够帮助您冻结或隐藏这些不必要的应用&#xff0…

最新PHP仿猪八戒任务威客网整站源码/在线接任务网站源码

资源介绍 老规矩&#xff0c;截图为亲测&#xff0c;前后台显示正常&#xff0c;细节功能未测&#xff0c;有兴趣的自己下载。 PHP仿猪八戒整站源码下载&#xff0c;phpmysql环境。威客开源建站系统&#xff0c;其主要交易对象是以用户为主的技能、经验、时间和智慧型商品。经…

Vue81-独享路由守卫

一、 独享路由守卫的定义 当只有某个特定的路由需要做校验的时候&#xff0c;可以在改路由组件规则的地方单独配置独属于改组件的路由守卫。 二、示例 1、需求 系统只在进入新闻路由页面的时候做校验。 2、代码实现 注意&#xff1a; 独享路由守卫&#xff0c;只有前置路由守…

高通安卓12-OTA 升级

1.OTA介绍 OTA 英文全称是 Over-the-Air Technology&#xff0c;即空间下载技术的意思。 OTA 升级是 Android 系统提供的标准软件升级方式。它功能强大&#xff0c;可以无损失升级系统&#xff0c;主 要通过网络[例如 WIFI、3G]自动下载 OTA 升级包、自动升级&#xff0c;但…

Windows11系统自动获取电脑IPV6地址,并且开机自动发送到指定邮箱

废话&#xff1a;最近放假回家&#xff0c;在家里突然想玩游戏了&#xff0c;Steamdeck性能终归有限。部分游戏始终玩的不爽&#xff0c;想到之前了解到的SunshnieMoonlight串流的方案&#xff0c;远程调用家里的电脑打游戏&#xff0c;简直不要太爽。 一顿折腾之后配置好了所有…

【职场人】“万事皆可”领导的职场囧途

故事单元一&#xff1a;无所不能的承诺 在我的公司里&#xff0c;有一位领导&#xff0c;我们戏称他为“万事皆可”先生。每当有新的任务或挑战出现时&#xff0c;他总是第一个站出来&#xff0c;拍着胸脯说&#xff1a;“没问题&#xff0c;交给我吧&#xff01;”他的这种自…

一种微弱故障特征增强的旋转机械故障诊断方法(MATLAB)

导致轴承失效的根本原因是由异常磨损和局部间的机械冲击所导致的。对轴箱轴承日常运转的下所产生的均匀磨损而言&#xff0c;其振动信号特征与正常轴承振动信号大致一样&#xff0c;随机性较强&#xff0c;其概率密度函数呈现出高斯分布的现象&#xff0c;但由于磨损所导致的不…

37 - 上级经理已离职的公司员工(高频 SQL 50 题基础版)

37 - 上级经理已离职的公司员工 selecte1.employee_id fromEmployees e1 left join Employees e2 on e1.manager_id e2.employee_id wheree2.manager_id is null and e1.manager_id is not null and e1.salary<30000;

《计算机英语》 Unit 5 Networking 网络

Section A Networking 网络 The need to share information and resources among different computers has led to linked computer systems, called networks, in which computers are connected so that data can be transferred from machine to machine. 不同计算机之间共享…

什么是正态分布

最重要的连续分布的通用名是概率密度函数&#xff0c;而标准正态分布&#xff08;Standard Normal Distribution&#xff09; 是最重要的概率密度函数。这个连续分布之所以重要&#xff0c;我认为是因为它非常常见&#xff0c;换句话说&#xff0c;我们会很常用到它。标准正态分…