Mitosis 编译 Vue 产物,模板含有 props.style 竟然会出错?

大家好,我是馋嘴的猫。最近在用 Mitosis 配合组件库的开发,但在编译为 Vue 的产物时,遇到了一个奇怪的编译问题。借助这个问题,重新认识了 Mitosis 和 Vue 的关键字限制。

请随我的正文,一起来探讨下吧~

问题

在编译 Mitosis 的模板文件时,如果文件里面含有props.style,则在打包 Vue 平台产物时会失败,并提示Error: avoid using JavaScript keyword as property name: "style"。

但同时,将此份模板文件编译为其他平台,如 React 和 Solid ,则正常无误。

问题复现 Playground

Mitosis Playground

可在 Mitosis Playground 的右边窗口选择 React、Solid、Vue 选项卡查看编译结果,仅在选择 Vue 时会出错,出错信息可在 Chrome 的 console 里查看。

Mitosis 出错源码

typescript 复制代码
export default function MyComponent(props) {
  return (
    <div style={props.style}/>
  );
}

分析

在编译 Vue 的时候出错提示为:

text 复制代码
Error: avoid using JavaScript keyword as property name: "style"

在 Mitosis 源码查找出错提示,发现为 getProps 方法抛出的错误,代码位置

继续追查下去,可以重现 Mitosis 在遇到"props.style"编译出错的全流程

出错流程解析

  1. Vue 的 generator 通过 getProps 方法收集所有的 props 属性,代码链接
typescript 复制代码
const props = Array.from(getProps(component));
  1. 在 getProps 方法里,匹配所有满足props.xxx的赋值,并且对 xxx 的值展开校验。

  2. 如果属性值命中了 prohibitedKeywordRE 的正则表达式(如props.style),则 Mitosis 会丢出错误 Error: avoid using JavaScript keyword as property name: "style" ,即本篇一开始提示遇到的错误。 代码链接

  3. 至此,全流程完结。

Mitosis为何要做这样的限制?

查看源码,发现 Mitosis 官方在一笔提交里加上了对 Vue 的关键字限制,代码链接

这笔提交,主要是两处关键字的限制,与 Vue 是对齐的,可对照 Vue 仓库的源码查看:

  1. utils.ts 里的限制,代码链接
typescript 复制代码
export const isReservedAttribute = makeMap('key,ref,slot,slot-scope,is')
  1. attrs.ts 里的限制,代码链接
typescript 复制代码
export const isReservedAttr = makeMap('style,class')
  1. 结合以上的限制,Vue 在 dev 模式下,会对不符合条件的 props,抛出 warning,代码链接
typescript 复制代码
if (__DEV__) {
  const hyphenatedKey = hyphenate(key);
  if (
    isReservedAttribute(hyphenatedKey) ||
    config.isReservedAttr(hyphenatedKey)
  ) {
    warn(
      `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,
      vm
    );
  }
}

Vue 为何要做这样的限制

那回过头来,Mitosis 是为了对齐 Vue 而做的关键字限制。那为什么 Vue 一开始就要做限制呢?

原因

Vue 支持透传特性,可以实现组件不声明 class、style 等属性,也能自动接收父组件的对应属性,并添加到根元素上,文档如下所示:

所以,在开发者使用 React jsx ,并使用props.style来实现接受父组件传进来的 style 时,Vue 中却是不需要这么实现的。

并且,Vue 还实现了 class 和 style 的自动合并,所以也可以说,Vue 从另外一方面,更不鼓励从 props 手动取 class 和 style 的值了。

鉴于以上的原因,Vue 对 props 数组加上了关键字限制,如 class、style 等。

关键字限制会影响 Mitosis 什么平台的编译?

  1. 首先,getProps 函数里的校验逻辑,是导致 props 关键字限制的直接原因。

  2. 其次,getProps 函数会被以下平台的 Mitosis generator 调用: Angular,Vue,Html,Lit,Stencil,Svelte,因此,这些平台打包时,都会受到关键字限制的影响。

结论

  1. Mitosis 作者对照 Vue 对 props 的关键字限制,在 Mitosis 的实现里添加了一样的关键字限制,导致了props.style 编译错误的发生。

  2. 因为关键字限制的校验仅在 getProps 方法会被调用,因此会导致如props.style在 Vue 上会编译出错,在 React 上却编译正常(因 React generator 没有调用 getProps 函数)

  3. 这些关键字限制是 Vue 独有的,但 Mitosis 官方却把此限制运用在 Angular,Vue,html,lit,stencil,svelte 这几个平台。可能是为了保证同一份 mitosis 能在所有平台都能编译,所以限制条件是取最苛刻的,没有做很完善的平台区分,但是这对于仅使用Angular、lit等框架的开发者是不太方便的(限制了本来没有必要限制的props)

  4. 在书写 Mitosis JSX 时,因为 Mitosis 的校验逻辑限制,导致即使开发者尝试通过 useStore 来实现 getter method,类似以下代码,也会报错:

typescript 复制代码
// still throws out error about "props.style"
const state = useStore({
  get myStyle() {
    return props.style;
  },
});
  1. 如果开发者只需要生成 React 和 Solid 产物,暂不会遇到此问题。但如果需要 Angular,Vue,Html,Lit,Stencil,Svelte 这几个平台的产物,则需要想办法绕开关键字限制,比如与父组件约定传入其它非限制 key 值的 props。
相关推荐
学网安的肆伍34 分钟前
【046-WEB攻防篇】注入工具&SQLMAP&Tamper编写&指纹修改&高权限操作&目录架构
前端·架构
森林的尽头是阳光1 小时前
tree回显问题
javascript·vue.js·elementui
weixin_BYSJ19871 小时前
「课设设计」springboot校园超市助购系统26449 (附源码)
java·javascript·spring boot·python·django·flask·php
Highcharts.js2 小时前
如何下载使用Highcharts Grid 开发web可编辑表格
前端·人工智能·grid 表格·web 表格·在线编辑表格·highcharts表格安装·表格开发工具
用户62960593247052 小时前
从“浏览器根本区分不了”到真正实现:刷新不退出,关闭标签页自动退出,前端判断浏览器关闭和刷新
前端
qetfw2 小时前
MWU:Vue 3 + FastAPI 的 MaaFramework 跨平台 WebUI 源码
前端·vue.js·python·fastapi·开源项目·效率工具
mfxcyh2 小时前
Vue3+Ant Design Vue 实现手动异步文件上传(含大小校验、弹窗上传)
前端·javascript·vue.js
wordbaby2 小时前
Web端热敏标签打印完整解决方案(QZ Tray + 译维A42)
前端
swipe2 小时前
03|Axios 请求进了后端之后:Controller、Request、Response 是怎么接住它的?
前端·后端·全栈
meilindehuzi_a2 小时前
Vue3进阶基础:指令修饰符、v-model表单绑定、动态样式、计算属性与侦听器实战
前端·javascript·vue.js