• Vue3组件库项目基础搭建


    总结我司组件库项目的基础搭建部分

     Monorepo环境

    就是指在一个大的项目仓库中,管理多个模块/包(package),这种类型的项目大都在项目根目录下有一个packages文件夹,分多个项目管理。大概结构如下:

    1. -- packages
    2. -- pkg1
    3. --package.json
    4. -- pkg2
    5. --package.json
    6. --package.json

    简单来说就是单仓库 多项目。

    使用pnpm

    npm install pnpm -g && pnpm init

    monorepo的实现

    接下就是pnpm如何实现monorepo的了。

    为了我们各个项目之间能够互相引用我们要新建一个pnpm-workspace.yaml文件将我们的包关联起来

    1. packages:
    2. - 'packages/**'
    3. - 'examples'

    这样就能将我们项目下的packages目录和examples目录关联起来了,当然如果你想关联更多目录你只需要往里面添加即可。根据上面的目录结构很显然你在根目录下新packages和examples文件夹,packages文件夹存放我们开发的包,examples用来调试我们的组件。examples里可以自行通过vue-cli创建vue3+vite项目来作为本地调试组件库的环境,很简单这里就不展开说了。

    新建包文件

    接下来就是要往我们的packages文件夹冲填充内容了。

    utils包

    一般packages要有utils包来存放我们公共方法,工具函数等

    既然它是一个包,所以我们新建utils目录后就需要初始化它,让它变成一个包;终端进入utils文件夹执行:pnpm init 然后会生成一个package.json文件;这里需要改一下包名,我这里将name改成比如@myown-ui/utils表示这个utils包是属于myown-ui这个组织下的。所以记住发布之前要登录npm新建一个组织;例如myown-ui。

    1. {
    2. "name": "@myown-ui/utils",
    3. "version": "1.0.0",
    4. "description": "",
    5. "main": "index.ts",
    6. "scripts": {
    7. "test": "echo \"Error: no test specified\" && exit 1"
    8. },
    9. "keywords": [],
    10. "author": "",
    11. "license": "ISC"
    12. }

    组件库包

    components是我们用来存放各种UI组件的包

    新建components文件夹并执行 pnpm init 生成package.json

    1. {
    2. "name": "myown-ui",
    3. "version": "1.0.0",
    4. "description": "",
    5. "main": "index.ts",
    6. "scripts": {
    7. "test": "echo \"Error: no test specified\" && exit 1"
    8. },
    9. "keywords": [],
    10. "author": "",
    11. "license": "ISC"
    12. }

    包之间本地调试

    进入components文件夹执行

    pnpm install @myown-ui/utils

    你会发现pnpm会自动创建个软链接直接指向我们的utils包;此时components下的packages:

    1. {
    2. "name": "myown-ui",
    3. "version": "1.0.0",
    4. "description": "",
    5. "main": "src/index.ts",
    6. "scripts": {
    7. "test": "echo \"Error: no test specified\" && exit 1"
    8. },
    9. "keywords": [],
    10. "author": "",
    11. "license": "ISC",
    12. "dependencies": {
    13. "@myown-ui/utils": "workspace:^1.0.1"
    14. }
    15. }

     你会发现它的依赖@myown-ui/utils对应的版本为:workspace:^1.0.0;因为pnpm是由workspace管理的,所以有一个前缀workspace可以指向utils下的工作空间从而方便本地调试各个包直接的关联引用。

    到这里基本开发方法我们已经知道啦;接下来就要进入正题了,开发一个button组件

    试着开发一个button组件

    在components文件夹下新建src,同时在src下新建button组件目录,在button目录下新建button.vue和index.ts。此时文件目录如下

    1. -- components
    2. -- src
    3. -- button
    4. -- button.vue
    5. -- index.ts
    6. -- package.json

    在button/index.ts将button.vue导出

    1. import Button from './button.vue'
    2. export default Button

    因为我们开发组件库的时候不可能只有button,所以我们需要一个components/index.ts将我们开发的组件一个个的集中导出

    1. import Button from './button'
    2. export {
    3. Button
    4. }

    好了,一个组件的大体目录差不多就是这样了,接下来请进入我们的examples来看看能否引入我们的button组件

    examples里使用button

    上面已经说过执行在workspace执行 pnpm i xxx的时候pnpm会自动创建个软链接直接指向我们的xxx包。

    所以这里我们直接在examples执行:pnpm i myown-ui

    此时你就会发现packages.json的依赖多了个

    "myown-ui": "workspace:^1.0.0"

    这时候我们就能直接在我们的测试项目下引入我们本地的components组件库了,启动我们的测试项目,来到我们的 examples/src/app.vue 直接引入Button

    1. <script lang="ts" setup>
    2. import { Button } from 'myown-ui'
    3. script>

    不出意外的话你的页面就会展示我们刚刚写的button组件了

    组件注册

    组件单个注册

    很多时候我们在vue中使用一个组件会用的app.use 将组件挂载到全局。比如这样

    1. import { createApp } from 'vue'
    2. import { Button } from 'myown-ui'
    3. const app = createApp(App)
    4. app.use(Button)
    5. app.mount('#app')

    要使用app.use函数的话我们需要让我们的每个组件都提供一个install方法,app.use()的时候就会调用这个方法;

    我们将button/index.ts调整为

    1. import button from './button.vue'
    2. const withInstall = (comp) => {
    3. comp.install = (app) => {
    4. //注册组件
    5. app.component(comp.name, comp)
    6. }
    7. return comp
    8. }
    9. const Button = withInstall(button)
    10. export default Button

    此时我们就可以使用app.use来挂载我们的组件啦

    组件全部注册

    在使用组件时我们也会一次性的把组件库的组件都注册了。比如这样

    1. import { createApp } from 'vue'
    2. import MyownUi from 'myown-ui'
    3. const app = createApp(App)
    4. app.use(MyownUi)
    5. app.mount('#app')

    在我们上面给每个组件都挂载了一个install方法的前提下,全局的组件注册其实不难,就是套多个循环而已。

    在components/index.ts下引入所有组件并导出install方法

    1. import * as components from './src/index'
    2. export * from './src/index'
    3. export default {
    4. install: (app) => {
    5. for (const comkey in components) {
    6. app.component(components[comkey].name, components[comkey])
    7. }
    8. }
    9. }

    其实withInstall方法可以做个公共方法放到工具库里,因为后续每个组件都会用到,这里等后面开发组件的时候再调整

    到这里组件开发的基本配置已经完成,最后我们对我们的组件库以及工具库进行打包,打包之前如果要发公共包的话记得将我们的各个包的协议改为MIT开源协议

    1. ...
    2. "license": "MIT",
    3. ...

    vite打包

    打包们这里选择vite,它有一个库模式专门为我们来打包这种库组件的。

    前面已经安装过vite了,所以这里直接在components下直接新建vite.config.ts(配置参数文件中已经注释):

    1. import { defineConfig } from "vite";
    2. import vue from "@vitejs/plugin-vue";
    3. export default defineConfig(
    4. {
    5. build: {
    6. target: 'modules',
    7. //打包文件目录
    8. outDir: "es",
    9. //压缩
    10. minify: false,
    11. //css分离
    12. //cssCodeSplit: true,
    13. rollupOptions: {
    14. //忽略打包vue文件
    15. external: ['vue'],
    16. input: ['src/index.ts'],
    17. output: [
    18. {
    19. format: 'es',
    20. //不用打包成.es.js,这里我们想把它打包成.js
    21. entryFileNames: '[name].js',
    22. //让打包目录和我们目录对应
    23. preserveModules: true,
    24. //配置打包根目录
    25. dir: 'es',
    26. preserveModulesRoot: 'src'
    27. },
    28. {
    29. format: 'cjs',
    30. entryFileNames: '[name].js',
    31. //让打包目录和我们目录对应
    32. preserveModules: true,
    33. //配置打包根目录
    34. dir: 'lib',
    35. preserveModulesRoot: 'src'
    36. }
    37. ]
    38. },
    39. lib: {
    40. entry: './index.ts',
    41. formats: ['es', 'cjs']
    42. }
    43. },
    44. plugins: [
    45. vue()
    46. ]
    47. }
    48. )

    这里我们选择打包cjs(CommonJS)和esm(ESModule)两种形式。

    其实到这里就已经可以直接打包了;components下执行: pnpm run build你就会发现打包了es和lib两个目录,但是打包的组件只能给js项目使用,在ts项目下运行会出现一些错误,而且使用的时候还会失去代码提示功能,这样的话我们就失去了用ts开发组件库的意义了。所以我们需要在打包的库里加入声明文件(.d.ts)。

    那么如何向打包后的库里加入声明文件呢? 其实很简单,只需要引入vite-plugin-dts

    1. import { defineConfig } from "vite";
    2. import vue from "@vitejs/plugin-vue"
    3. import dts from 'vite-plugin-dts'
    4. export default defineConfig(
    5. {
    6. build: {...},
    7. plugins: [
    8. vue(),
    9. dts({
    10. //指定使用的tsconfig.json为我们整个项目根目录下掉,如果不配置,你也可以在components下新建tsconfig.json
    11. tsConfigFilePath: '../../tsconfig.json'
    12. }),
    13. //因为这个插件默认打包到es下,我们想让lib目录下也生成声明文件需要再配置一个
    14. dts({
    15. outputDir:'lib',
    16. tsConfigFilePath: '../../tsconfig.json'
    17. })
    18. ]
    19. }
    20. )

    因为这个插件默认打包到es下,我们想让lib目录下也生成声明文件需要再配置一个dts插件,暂时没有想到其它更好的处理方法~

    然后执行打包命令你就会发现你的es和lib下就有了声明文件

    其实后面就可以进行发布了,发布之前更改一下我们components下的package.json如下:

    1. {
    2. ...
    3. "main": "lib/index.js",
    4. "module":"es/index.js",
    5. "files": [
    6. "es",
    7. "lib"
    8. ],
    9. ...
    10. }

    解释一下里面部分字段

    module

    我们组件库默认入口文件是传统的CommonJS模块,但是如果你的环境支持ESModule的话,构建工具会优先使用我们的module入口

    files

    files是指我们需要发布到npm上的目录,因为不可能components下的所有目录都被发布上去

    开始发布

    其实npm发包是很容易的,发布之前记得到npm官网注册个账户,如果你要发布@xx/xx这种包的话需要在npm新建个组织组织组织名就是@后面的,注册后npm login然后npm publish,再次发布的话记得更改版本号。

    其实也可以写个脚本自动化打包和发布,这里就不展开说了。

    最后

    其实开发一个组件库并不难,把基础的架构设计搭好了,剩下的组件更多的是业务功能上的开发。也可以去看看Antd、Element这些组件库的源码,借鉴下它们的设计思想。

  • 相关阅读:
    项目:后台管理系统的开发及自动化部署
    Pgsql函数编写
    NTP服务器工作原理
    openGauss3.1.0 版本的gs_stack功能解密
    Vu3笔记_02setup与常用的Composition API(组合式API)
    浅谈sealos及使用sealos4.0部署Kubernetes(K8s)高可用集群
    计算机毕业设计之java+SSM酒店客房预定管理系统
    MySQL数据库设计规范及SQL规范
    Linux下如何打包库供别人使用
    Windbg 快速定位C# 动态库依赖问题
  • 原文地址:https://blog.csdn.net/sanstu/article/details/128037762