主题
实现JSX
本节课代码地址(请参考课程获取) React项目结构:
react(宿主环境无关的公用方法)react-reconciler(协调器的实现,宿主环境无关) 各种宿主环境的包shared(公用辅助方法,宿主环境无关) 本节课将实现的JSX转换属于react包。
JSX转换是什么
JSX转换 playground
import { jsx as _jsx } from"react/jsx-runtime";
/*#__PURE__*/_jsx("div", {
children: "123"
});//或
/*#__PURE__*/React.createElement("div", null, "123");包括两部分: 编译时 运行时:jsx 方法或React.createElement 方法的实现(包括dev、prod两个环境) 编译时由babel 编译实现,我们来实现运行时,工作量包括: 实现jsx 方法 实现打包流程 实现调试打包结果的环境
实现jsx方法
包括: jsxDEV方法(dev环境) jsx 方法(prod环境)
React.createElement 方法实现打包流程 对应上述两3方法,打包对应文件:
react/jsx-dev-runtime.js (dev环境)
react/jsx-rumtime.js (prod环境)
React打包流程中需要安装的rollup plugin 与node 包:
bash
pnpm i -D -w rimraf rollup-plugin-generate-package-json rollup-plugin-
typescript2 @rollup/plugin-commonjs调试打包结果 pnpm link文档 这种方式的优点:可以模拟实际项目引用React 的情况 缺点:对于我们当前开发big-react 来说,略显繁琐。对于开发过程,更期望的是热更新效 果。 补充知识
@rollup/plugin-commonjs 插件的作用
rollup 原生支持ESM 格式,所以对于CJS 格式的包,我们需要先将它用该插件转为ESM 格式。 这里使用该插件是因为他是rollup 中最常见的插件,加上有备无患。
执行pnpm link --global 时报错
如果报如下错误:
ERROR Unable to find the global bin directory结局方案参考解决pnpm 升级之后全局安装出现异常问题
影响JSX 转换的因素
有些同学发现:在源码中jsx 的key 属性是第三个传参,但视频中实现createElement 时 是从config 参数中获取。造成这些区别的原因如下: 在测试用例(后续课程会实现)中使用的是createElement ,在打包后代码中使用的 是jsx 。虽然这两者最后都是生成ReactElement ,但他们的传参是不同的。 jsx 的参数如下: 对于开发环境,jsxDEV 参数依次为type 、props 、key 、source 、self 。其 中后两者为开发环境用于调试的参数 对于生产环境,jsx 参数依次为type 、props 、keykey 作为一个单独的传参,为了体现了他的特殊性(与节点稳定相关),所以与其他props 区分开。 createElement 的参数依次为type 、props 、...children 。其中children 及后续其 他传参经过转换都会作为children 属性,比如对于:
jsx
<ul>
<li>1</li>
</ul>
<ul>
<li>1</li>
<li>2</li>
</ul>转换结果为:
React.createElement("ul", null,
React.createElement("li", null, "1")
);
React.createElement("ul", null,
React.createElement("li", null, "1"),
React.createElement("li", null, "2")
);createElement 与jsx 之所以会有这些区别更详细的原因可以参考createlement-rfc 所以结论是,由于以下情况传参都有区别:
createElement 与jsxjsx 在生产环境与开发环境 所以我们起码需要实现createElement 与jsx 这2个API ,如果为了更高的源码还原度, 我们甚至应该实现3个版本(createElement 与生产、开发环境下的jsx ),以应对使用不 同API 的场景(比如对于部分测试用例,使用的是createElement ) 本节课程没有区分jsx 与createElement ,这是不严谨的。这么做可能造成的后果之一是 「由于key传参位置不同,导致在某些情况下key丢失」。比如应该用jsx 的场景(key 是 第三个参数),使用了createElement (key 在第二个参数props 中),就会导致key 被 当成createElement 的children prop ,进而导致key 丢失。解决办法如下,学员可自行 更新到代码中: fix: jsx与createElement实现一致导致key丢失的问题 纠错
jsx-runtime的output中输出格式参数名应为format而不是formatereact的output中name字段的值应为react而不是index.js对于umd的格式,如果是以esm引入,则两者没有区别。但如果在浏览器引入,前者会挂 载window.react,而后者会挂载window.index。 详见rollup文档#outputname