6

vue3 使用有感 - rxliuli blog

 2 years ago
source link: https://blog.rxliuli.com/p/930763abc6ae4cfbbb45bc17a9947596/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

假若没有看见光明,我本可以忍受黑暗。

自上家公司从去年 5 月份开始成功推广 react 之后,很长一段时间吾辈一直在使用它,而今年,离职之后新的公司再次使用 vue3,再次见证了两个 team 踏入了同一条河流。不过 vue 作者说 vue3 使用 ts 重写,对其支持很好,吾辈姑且安心了一点,但经过近一个月的实践,吾辈还是发现了种种问题。

从 vue 迁移到 react 的原因参考: 2020 吾辈在公司推动的前端技术演进

  • vue3 的生态不稳定,而且仍然比较小
  • vue3 和 ts 的结合仍然不算好
  • webstorm/vscode 对 vue3+ts 的支持比较糟糕

vue3 的生态

vue 官方承认自身社区比 react 更小,但他们很明智的没有说出来,这究竟代表了什么。

  • vue+ts 结合的体验很糟糕,下面会详述
  • vue 的大版本升级虽然没有 react 那么快,但每次升级都是完全破坏性的,整个社区都要重新构建
  • ant-design-vue 2 使用 vue3 重构,但使用体验仍然比不上官方的 ant-design(例如 Table 的能力还远远比不上 ant-design)
  • antv 系列官方基本优先或仅支持 react,例如只有 react 版本的 G2Plot/Graphin
  • 结合 storybook 有点恶心,需要在字符串中写模板
  • vue-router 开发环境和生产环境的行为不一致,开发环境支持 import(),生产环境则必须是 () => import()
  • 许多周边 npm 包都是 next/beta/rc 版本

vue+ts 结合

  • 模板是个失败的设计,很多问题都是由模板衍生而来
  • props 和 ts 结合仍有问题
  • 模板中只能编写 js,但 vue-tsc 会使用 tsc 检查,这会导致一些奇怪的问题很难解决
  • 使用 tsx 也会存在一些问题,但可能是现有条件下最好的解决方案(antdv 使用该方式),参考:极致的开发体验!Vite + Vue 3 + tsx 完整教程

vue 模板到底有什么问题?

相比于 vue 模板,jsx(或者说 react)的设计非常巧妙,它不需要 props/attrs/emits/slot/指令 这一系列 vue 的功能,而仅仅只需要 props,而它能够使得 dts 就能够完全支持 react 组件的接口定义,进而使编辑器能够通过 ts 做提示、导航和重构。而 vue 一时看起来方便开发者的设计,例如 props 支持定义类型、必填校验及 getter/setter,未在 props 声明的属性会被放到 attrs 并自动绑定到组件根元素上,前者在和 ts 结合时导致要重复定义 props 的类型,后者导致在支持 fragments 时反而需要手动指定绑定 attrs 的元素。

下面是一个 antdv List 组件的使用示例,如果不看文档,没人知道 slot 到底可以挂的是羊头,还是狗肉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<a-list item-layout="horizontal" :data-source="data">
<a-list-item slot="renderItem" slot-scope="item, index">
<a-list-item-meta
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
>
<a slot="title" href="https://www.antdv.com/">{{ item.title }}</a>
<a-avatar
slot="avatar"
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</a-list-item-meta>
</a-list-item>
</a-list>
</template>

vscode vetur 和 jetbrians(web-types) 为了解决开发体验的问题选择了两条不同的道路,但都存在一些问题,参考:web-types.json 目前仍然有问题,包括某些 slot/item 仍然是错误的,可以想见,既然连 antdv 这么流行的 vue ui 组件库都无法保证没有问题,更别提整个 vue 生态中的其他 ui 组件库了。

props 和 ts 结合还有什么问题?

props 在 vue3 的 ts 有所增强,至少能够使用 PropType 复杂类型了,例如下面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { defineComponent, PropType } from "vue";
interface User {
name: string;
age: number;
}

export default defineComponent({
name: "List",
props: {
// 使用 PropType 定义复杂类型
list: Array as PropType<User[]>,
},
setup(props) {
// 这儿的 props 类型是正确的
console.log(props.list);
return {};
},
});

但它仍然存在一些问题

无法复用现有的类型。例如当我们已经有一个后端返回的数据结构类型了,而我们希望组件仅需要其中的部分字段,而这无法使用 ts 的类型操作完成。究其原因,还是因为 vue 的 props 定义仍然是值而非类型。
无法使用 ts 的可选属性。vue props 仍保留定义 required/default/validator 的功能,所以并不能使用 ts 的可选属性。下面的示例代码将上面限制表现的的淋漓尽致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// react
interface User {
name: string;
age?: number; // 利用了 ts 的可选属性
address: string;
}
// 使用 ts 的类型操作,只取 name/age 字段
const User: React.FC<Pick<User, "name" | "age">> = (props) => {
return (
<div>
{props.name} {props.age}
</div>
);
};
// vue
defineComponent({
name: "User",
props: {
// 重新定义,和 ts 格格不入
name: {
type: String,
required: true,
},
age: Number,
},
});

无法使用泛型。最典型的莫过于 List 组件,我们希望传入的 data 数据决定 slot 中参数的类型,目前这是不可能的。下面是 react 中的泛型组件示例(本质上是泛型函数,对 state=>ui 的抽象是真的彻底)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 定义泛型函数
function List<T>(props: {
list: T[];
renderItem(item: T, i: number): ReactNode;
}) {
return <ul>{props.list.map(props.renderItem)}</ul>;
}

interface User {
name: string;
age?: number;
}

export const Hello: React.FC = () => {
return (
<List
list={[{ name: "琉璃" }] as User[]}
renderItem={(item, i) => <li key={i}>{item.name}</li>}
/>
);
};

模板中只能编写 js,但 vue-tsc 会使用 tsc 检查,这会导致一些奇怪的问题很难解决

模板里不能使用 ts,但 vue-tsc 却会检查 ts,然后就 GG 了

如上图,就因为模板中的函数参数没有指定类型导致 vue-tsc 报告错误了,但模板中也确实不能定义参数类型,所以目前只能将之放到 script 中并在 setup 函数返回(是不是感觉挺蠢的?)

webstorm/vscode 对 vue3+ts 的支持比较糟糕

具体表现在提示、导航和重构。吾辈在想,是不是 vue 的开发者都习惯了这种问题,代码导航靠 C-F 一个个查找,重构时 CS-F 一个个手动替换(群友吐槽说:“不然怎样,就 vue 那个框架设计,完全不考虑静态分析好吧……估计反馈给 yyx,得到的回答是:这么爱静态分析,滚去用 angular”)

  • 在 monorepo 中 vue-ts 提示很慢
  • monorepo 中同时包含 react 子模块时,无法使用 vue tsx,webstorm 会默认为是 react tsx
  • 重构不支持自动重命名 ref/setup 返回值/模板引用

一些感受到的优点

上面吐槽了那么多,vue 及其社区也并非没有可取之处

  • vue3 的 hooks api 对心智负担确实更小,不太容易出现 react hooks 的依赖问题
  • vite/vuepress 很好用,比 snowpack/docusaurus 更好用(即便吾辈使用的是 react 技术栈,但仍然使用它们作为构建和文档工具)

上面只是吾辈的一些吐槽,但考虑到成本问题,在公司推广 react 短期来看仍然是不现实的(vue3、ts 甚至 esnext 都有人未能基本掌握)。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK