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。
相关推荐
二十雨辰10 分钟前
歌词滚动效果
前端·css
法医11 分钟前
和文心快码做朋友,让编程像“说话”一样简单
前端·文心快码
前端小巷子15 分钟前
JS 打造「放大镜 + 缩略图」一体组件
前端·javascript·面试
陈随易16 分钟前
适合中国宝宝的AI编程神器,文心快码
前端·后端·node.js
知识分享小能手19 分钟前
React学习教程,从入门到精通,React AJAX 语法知识点与案例详解(18)
前端·javascript·vue.js·学习·react.js·ajax·vue3
UrbanJazzerati32 分钟前
掌握 DOM 的基础属性与方法:从操作元素到构建动态效果
前端·面试
hashiqimiya1 小时前
html实现右上角有个图标,鼠标移动到该位置出现手型,点击会弹出登录窗口。
前端·html
古夕1 小时前
前端文件下载的三种方式:a标签、Blob、ArrayBuffer
前端·javascript·vue.js
纯真时光1 小时前
Vue3中pinia状态管理库的使用(Composition API 风格)
前端
李李记1 小时前
Node.js 打包踩坑?NCC+PKG 从单文件到多平台可执行文件,解决 axios 缺失等 80% 问题
javascript