【从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,一经查实,立即删除!

相关文章

秋招的复习随想

文章目录 第一版第二版第三版 第一版 研二准备秋招了&#xff0c;真想对研一的我说&#xff01; 课这个东西&#xff0c;还看不出来老师到底是想不想教吗&#xff1f;大部分都是浪费时间&#xff0c;下课让你交论文&#xff0c;实际论文都不会看&#xff0c;都是助教改的。然后…

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

目录 一、唯一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;可进行参考。 /** 过滤出已经安装的包…

工业用焦炉集气管压力控制状态远程预警方法

工业用焦炉集气管压力控制状态远程预警方法 一、项目提出前状况: 焦化厂焦炉集气管压力是炼焦生产过程中重要的工艺参数(其控制目标80~120Pa),焦炉集气管压力的稳定是焦炉正常生产的重要保证。集气管压力过高会造成焦炉炉体冒烟冒火,污染环境,对操作人员的人身安全构成…

不同交换机之间相同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…

35.netty模拟redis客户端向redis服务端写数据

redis命令:set name zhangsan *3 $3 set $4 name $8 zhangsan *3 表示有三个元素 $3表示 set 命令的长度,3个字节 $4 表示name的长度,4个字节 $8 表示zhangsan的长度,8个字节 package com.xkj.nian;import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteB…

【专业英语 复习】第4章 System Software

1. Most operating systems support the ability to switch between different applications. This is called ____. A driving B multitasking C translating D booting 正确答案&#xff1a;B &#xff08;多任务处理&#xff09; 大多数操作系统支持在不同应用程…

OPENCV中0x00007FFE5F35F39C发生异常

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

git-pull详解

NAME git-pull - Fetch from and integrate with another repository or a local branch SYNOPSIS git pull [<options>] [<repository> [<refspec>…​]] DESCRIPTION Incorporates changes from a remote repository into the current branch. If the…

js如何把数组网页元素按分隔符返回字符串?document.getElementsByClassName(“class1“)

要将数组中的网页元素按分隔符返回字符串&#xff0c;你可以使用 JavaScript 中的 Array.prototype.map() 方法和 Array.prototype.join() 方法。 首先&#xff0c;使用 document.getElementsByClassName("class1") 获取到指定类名的所有网页元素&#xff0c;并将其…

ChatTTS,智能聊天机器人,深度学习技术!\n\n标题建议ChatTTS智能聊天机器人的开源之旅。

**项目介绍**&#xff1a;  ChatTTS是一个基于自然语言处理和深度学习技术的智能聊天机器人项目。它利用了开源的Gensim和NLTK库进行文本分析&#xff0c;并结合了TensorFlow或PyTorch等深度学习框架&#xff0c;构建了一个强大的自然语言处理模型。ChatTTS能够理解并生成人类…

UE开发随笔------json与struct互相转换(FJsonObjectConverter)

UStruct定义&#xff1a; USTRUCT() struct FHeartBeatMsg {GENERATED_BODY() public:UPROPERTY()FString pcCode TEXT("");UPROPERTY()FString deviceType TEXT("");UPROPERTY()FString messageType TEXT("");UPROPERTY()FString content …

LLm与微调入门

两种 Finetune 范式 增量预训练微调 使用场景&#xff1a;让基座模型学习到一些新知识&#xff0c;如某个垂类领域的常识 训练数据&#xff1a;文章、书籍、代码等 指令跟随微调 使用场景&#xff1a;让模型学会对话模板&#xff0c;根据人类指令进行对话 训练数据&#…

C++记录程序运行时间的4方法

目录 1. 使用 <chrono>库&#xff08;C11及以后版本&#xff09; 2. 使用<ctime>库&#xff08;较旧但常用的方法&#xff09; 3、使用第三方库&#xff08;如Boost.Timer&#xff09; 4. 使用Windows API函数&#xff08;Windows平台特有&#xff09; 1. 使用 …

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;…