React项目结构:
- 
react(宿主环境无关的公用方法)
- 
react-reconciler(协调器的实现,宿主环境无关)
- 
各种宿主环境的包 
- 
shared(公用辅助方法,宿主环境无关)
本节课将实现的JSX转换属于react包。
JSX转换是什么
JSX转换 playground (opens in a new tab)
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包:
pnpm i -D -w rimraf rollup-plugin-generate-package-json rollup-plugin-typescript2 @rollup/plugin-commonjs调试打包结果
pnpm link文档 (opens in a new tab)

这种方式的优点:可以模拟实际项目引用React的情况
缺点:对于我们当前开发big-react来说,略显繁琐。对于开发过程,更期望的是热更新效果。
补充知识
@rollup/plugin-commonjs插件的作用
rollup原生支持ESM格式,所以对于CJS格式的包,我们需要先将它用该插件转为ESM格式。
这里使用该插件是因为他是rollup中最常见的插件,加上有备无患。
执行pnpm link --global时报错
如果报如下错误:
ERROR  Unable to find the global bin directory结局方案参考解决pnpm 升级之后全局安装出现异常问题 (opens in a new tab)
影响JSX转换的因素
有些同学发现:在源码中jsx的key属性是第三个传参,但视频中实现createElement时是从config参数中获取。造成这些区别的原因如下:
- 在测试用例(后续课程会实现)中使用的是createElement,在打包后代码中使用的是jsx。虽然这两者最后都是生成ReactElement,但他们的传参是不同的。
jsx的参数如下:
- 
对于开发环境, jsxDEV参数依次为type、props、key、source、self。其中后两者为开发环境用于调试的参数
- 
对于生产环境, jsx参数依次为type、props、key
key作为一个单独的传参,为了体现了他的特殊性(与节点稳定相关),所以与其他props区分开。
createElement的参数依次为type、props、...children。其中children及后续其他传参经过转换都会作为children属性,比如对于:
<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 (opens in a new tab)
所以结论是,由于以下情况传参都有区别:
- 
createElement与jsx
- 
jsx在生产环境与开发环境
所以我们起码需要实现createElement与jsx这2个API,如果为了更高的源码还原度,我们甚至应该实现3个版本(createElement与生产、开发环境下的jsx),以应对使用不同API的场景(比如对于部分测试用例,使用的是createElement)
本节课程没有区分jsx与createElement,这是不严谨的。
rollup 的 output 中 name 字段作用
name 主要用于 UMD 和 IIFE 模块格式,使用 es 则不需要设置
当使用这两种模块格式时,Rollup 需要知道将哪个名称(也就是 name 选项的值)添加到全局命名空间(即,window 对象)。
如 name:react 其实 打包之后会在全局对象中出现 window.react 属性,可以直接访问。