怎么封装一个Vue3 Ts组件库?

前言

最近被封装组件库这件事折磨了两天,网上的教程大多需要再进行本地调整,于是想总结记录下搭建组件库的过程.

为什么要使用Ts封装组件库?

使用Ts可以让我们在使用组件库的时候获得十分友好的类型提示,习惯使用ts是必要的!

使用Vite创建一个Vue3+Ts项目

这里我使用的npm:

1
npm create vite

接下来选择Vue模板和Ts模板..

完成后如下:

使用Vite创建项目

为了演示一个不带文档展示功能的组件库,我们需要精简下项目结构带来可读性

创建完项目后我们来精简下项目结构:

删去src下的components文件夹,在项目根目录创建一个packages文件夹来存放我们自己写的组件

精简项目结构

组织packages下的文件夹结构

这个文件夹在我们封装组件库时非常重要,之后我们使用vite打包的目标目录就是它

因此提前规划一个组织良好的文件结构非常重要

这里是以我的风格来举例,也可也使用自己的风格来组织

拿Button组件举例

看如下图:

Button组件的文件夹结构

我们来分析下Packages是怎么管理Button的:

packages

packages根目录下有两个东西,一个是Button文件夹,应该放所有与Button组件相关的内容(比如说逻辑,样式…)

另一个是index.ts文件,该文件通过各组件文件夹根目录下的index.ts用来统一导出所有组件,也是我们组件库的核心入口文件。

Button目录

根目录下有一个src目录,里面放着Button.vue这个单文件组件,当然这里是举个非常简单的例子,之后应该要拆分样式与逻辑;

然后像packages一样,也有一个index.ts,用来导出Button组件。

Button.vue

这里写了一个非常简单的例子,一个需要props来展示内容的按钮组件

Button.vue里

Button下的index.ts

用来导出src下的Button组件,我们来看看是啥样的:

Button目录下的index.ts

可以看到我们直接导入了Button.vue这个单文件组件(好方便!),然后将这个组件封装成一个单独的注册插件以便实现按需导入,最后再导出Button组件本体,这样就提供了两种方式让别人使用我们的组件。

packages下的index.ts

来看看它是怎么统一导出的.

packages下的index.ts

在这里我们导入了Button目录下的注册组件的插件,然后再封装成了一个注册插件,并且将其作为默认导出

因为这里只有一个组件,所以作用看起来不明显,在组件多了之后我们就可以继承各组件的注册插件来封装一个全局安装的插件,就像我们使用的app.use(…)后可以全局使用组件一样,

然后再二次导出Button下的所有内容,这也是为了实现按需导入。

使用我们刚封装的Button组件

接着我们再App.vue中导入一下packages下的Button看看能不能正常使用

使用Button组件

然后跑起来

1
npm run dev

效果图如下:

Button组件的效果图

这里按钮的样式有点不一样,是因为我用了脚手架自动创建的全局样式

非常好,到这里我们已经完成了本地测试,接下来该打包,发布了。

打包

安装相关依赖

要使用vite打包成带有d.ts的类型声明文件,我们需要安装一个vite插件: vite-plugin-dts

1
npm i vite-plugin-dts -D

主要要加上 -D 后缀来表明这是一个开发环境的依赖

接着我们还需要安装@types/node这个node标准库的类型声明库

1
npm i @types/node -D

同样也需要标注 -D

vite.config.ts中的配置(重点!!!)

这里总结了一份比较稳定的配置写法,可以根据情况自定义…

vite.config.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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import dts from "vite-plugin-dts";
//要用到path.resolve来处理绝对路径
import path from "node:path";


export default defineConfig({
//构建配置
build: {
//告诉vite以库模式构建
lib: {
//指定打包的格式,一般这三个就够用了
formats: ['cjs','es','umd'],
//入口文件,注意要使用绝对路径
entry: path.resolve(__dirname, "./packages/index.ts"),
//库的名称,用来区分用的
name: "Tyee",
//打包出来的文件名,注意这里要和入口文件一样,因为d.ts是基于同名文件的
fileName: "index",
},
//rollup配置项
rollupOptions: {
//要处理的依赖
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
},
},
},
//配置插件
plugins: [
vue(),
//使用dts插件
dts({
// 以packages文件夹作为入口,构建d.ts文件,注意要使用绝对路径
include: path.resolve("./packages"),
}),
],
});

打包试试

写好了配置就到了打包环节

运行:

1
npm run build

打包完出现了dist目录,这就是我们封装的组件库:

打包后的组件库

可以看到了已经生成了对应的d.ts的类型声明文件,这样使用组件的时候就可以获得类型提示了!

测试打包后的组件库

到这一步马上就要成功了,让我们试试能不能成功引入dist下的组件

引入dist下的组件

Vue,启动!

1
npm run dev

引入dist成功

小坑

如果你的组件使用了任何样式,那么打包后会被打包成一个独立的css文件,因此外部使用的时候需要额外引入包内的css文件,不然样式无法生效

发布

这里不详细说明使用npm发布的步骤,只简单介绍一下怎么配置package.json

小坑: 发布时要切换至npm官方源,不然无法发布的,这里推荐nrm这个工具来换源

简单介绍package.json.png

这里提供具体代码,可以根据需要自行修改

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
{

"name": "xxxx",

"private": false,

"version": "0.1.4",

"type": "module",

"main": "./dist/index.cjs",

"umd:main": "./dist/index.umd.js",

"module": "./dist/index.js",

"types": "./dist/index.d.ts",

"scripts": {

"dev": "vite",

"build": "vue-tsc && vite build",

"preview": "vite preview"

},

"dependencies": {

"tyee-cocle": "^0.1.4",

"vue": "^3.3.4"

},

"devDependencies": {

"@types/node": "^20.6.2",

"@vitejs/plugin-vue": "^4.2.3",

"typescript": "^5.0.2",

"vite": "^4.4.5",

"vite-plugin-dts": "^3.5.3",

"vue-tsc": "^1.8.5"

},

"files": [

"dist"

]

}

当然json文件里不能写注释,同时包名要满足一定的格式

小坑

注意这里有个小问题,那就是dependencies下有我们自己的包,这是测试的时候引入的,发布时要注意删除

当项目越来越大,开发组件所需的依赖越来越多时,建议单独创建一个项目来专门发布dist目录的包,因为dist目录已经包含了所需的依赖包,不必在package.json下添加依赖。测试组件可以在开发组件的那个项目进行。

测试发布的包

测试自己发布的包

可以看到成功了!


怎么封装一个Vue3 Ts组件库?
https://azzellz.github.io/2023/09/18/封装一个Vue3 Ts组件库/
作者
Tyee
发布于
2023年9月18日
许可协议