基于vite从0-1创建一个vue3组件库(一)

1,766 阅读2分钟

1.组件库目标

首先,明确一波这次搭建的组件库的构建目标,是一个基于vue3+typescript的组件库。

2.项目初始化

首先使用vite 创建一个vue3,ts的项目

yarn create vite my-ui --template vue-ts

创建完毕后的目录如下

image.png

接下来,我们增加一些用于组件库的文件目录

image.png

编写一个组件Hello

// packages/components/Hello/index.vue
<template>
<h1>Hello {{ msg }}!</h1>
</template>

<script setup lang="ts">
defineProps<{ msg: string }>()
</script>
<script lang="ts">
// output component name
export default {
    name: 'Hello'
}
</script>

为了让组件库既允许全局调用,也可以局部调用,我们需要为每一个组件定义一个VuePlugin的引用方式

import Hello from './index.vue'

Hello.install = function(Vue: any) {
    Vue.component(Hello.name, Hello)
}

export default Hello

这下Hello组件就完成了,接下来就是在component主入口输出该组件

import Hello from './Hello';

const components = {
  Hello,
};

const install = function (Vue: any) {
  Object.values(components).forEach((component) => {
    console.log(component);
    Vue.component(component.name, component);
  });
};

if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue);
}

export { default as Hello } from './Hello';
export default { install };

到这里,Hello组件的编写和导出就完成了。接下来我们尝试一下使用全局注册的方式来进行组件的使用。
这时候我们回到src/main.ts进行组件注册

import { createApp } from 'vue'
import App from './App.vue'
import MyUI from '../packages/components'

createApp(App).use(MyUI).mount('#app')

在app.vue使用Hello查看效果

<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
</script>

<template>
  <Hello msg="world" />
</template>

image.png

组件库打包

这里我们可以参考vitebuild:lib
首先在根目录增加一个script文件夹,创建一个lib.config.ts文件

import { defineConfig } from 'vite';
import path from 'path';
import vue from '@vitejs/plugin-vue';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  build: {
    lib: {
      entry: path.resolve(__dirname, '../packages/components/index.ts'),
      name: 'my-ui',
      fileName: (format: string) => `my-ui.${format}.js`,
    },
    rollupOptions: {
      external: Object.keys(require('../package.json').peerDependencies),
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
});

修改package.json

{
  "name": "my-ui",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview",
    "build:lib": "vite build --config ./script/lib.config.ts"
  },
  "devDependencies": {
    "vue": "^3.2.25",
    "@types/node": "^17.0.5",
    "@vitejs/plugin-vue": "^2.0.0",
    "typescript": "^4.4.4",
    "vite": "^2.7.2",
    "vue-tsc": "^0.29.8"
  },
  "peerDependencies": {
    "vue": ">=3.2.25"
  },
  "files": [
    "dist"
  ],
  "main": "./dist/my-ui.umd.js",
  "module": "./dist/my-ui.es.js",
  "exports": {
    ".": {
      "import": "./dist/my-ui.es.js",
      "require": "./dist/my-ui.umd.js"
    }
  }
}

执行

yarn run build:lib

我们可以得到如下结果

image.png
这里会有一个问题,我们打包出来的库没有声明文件。 这时候可以用一个vite-plugin-dts来生成*.d.ts文件,接下来更改lib.config.ts文件

+ import dts from 'vite-plugin-dts';
  plugins: [
    vue(),
+   dts({
+      include: [
+        'packages/**/*.ts',
+        'packages/**/*.d.ts',
+        'packages/**/*.tsx',
+        'packages/**/*.vue',
+      ],
+    }),
  ],

接下来在package.json文件中配置types

{
 "types": "./dist/packages/components/index.d.ts",
}

image.png

最后就是npm发布,这个我就不多赘述了。。

大功告成!有点累,下次再讲怎么实现组件库文档和预览效果。