在我司内部的组件库的开发和打包常常让人头疼。面对各种五花八门的打包工具和复杂的配置文件,没有接触过的同事往往感到无从下手,甚至连高级开发者也可能会被过于复杂的配置所困扰。

所以,我一直在研究如何通过一种技术栈,能够简单、更高效的来完成组件库的开发和打包。

这篇文章将向你展示如何仅使用 Vite 轻松搞定 Vue3 组件库的打包工作。更好的是,我已经准备了一个开箱即用的项目模板 —— starter-lib-vue3 (https://github.com/starter-collective/starter-lib-vue3)

  • 支持多种模块格式(ESM、UMD、CJS)的组件库打包;
  • 支持全局导入、按需导入、自动导入等主流功能;
  • 提供组件库在线文档,支持组件展示和代码片段;
  • 相较主流组件库,几乎为 “零” 的配置成本;
  • 规范的版本管理和日志自动生成;

如果你对配置不感兴趣,该模板开箱即用,让你可以在最短的时间内上手开发。

一、为什么选择 Vite

Vite 的设计初衷就是“零配置开箱即用”,无需编写复杂的配置文件。对比传统工具,Vite 几乎不需要任何繁琐的环境搭建过程,让开发者能够将更多精力集中在实际的业务逻辑上。同时,Vite 拥有一个活跃的社区和丰富的插件生态,几乎可以满足任何开发需求。

Vite 在打包阶段基于 Rollup,可以轻松生成多种模块格式(如 ESM、UMD、CJS),满足组件库在各种场景下的使用需求。无论是现代浏览器、传统项目还是 Node.js 环境,Vite 都能很好地胜任。

Vite 库模式

在了解 Vite 的核心优势之后,你可能已经对它在开发阶段的强大表现印象深刻。然而,Vite 的能力并不仅限于开发,它在生产环境中同样表现出色(其生产环境基于 Rollup 扩展),特别是在构建组件库时,Vite 的 库模式(Library Mode) 提供了一个专门为打包库而优化的解决方案。

Vite 文档关于库模式的介绍:cn.vite.dev/guide/build…

Vite 的库模式是一种特殊的构建模式,旨在帮助开发者高效地将代码打包成可以复用的库或组件。通过库模式,Vite 可以轻松生成支持多种模块格式(如 ESM、UMD、CJS)的产物,适配各种场景。

以下是一个典型的库模式配置示例:

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

export default defineConfig({
  plugins: [vue()],
  build: {
    lib: {
      // 入口文件,指向你的组件库的主文件
      entry: './src/index.js',
      // 库的名称
      name: 'MyLibrary',
      // 导出的模块格式
      formats: ['es', 'umd', 'cjs'],
      // 打包后文件名
      fileName: (format) => `my-library.${format}.js`,
    },
    rollupOptions: {
      // 确保外部化处理不需要打包的依赖
      external: ['vue'], // 排除 Vue
      output: {
        // 在 UMD 模式下为外部化的依赖提供全局变量
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
});

从示例代码中看到,配置非常简单,不需要引入额外的插件,即可实现我们需要的产物输出。

接下来本文将带你一步步了解如何通过 Vite 实现专属你的组件库:

二、从零开始搭建组件库

1. 搭建 Vite 开发环境

运行 pnpm init ,初始化一个空的 package.json 文件。

运行 pnpm add vite typescript vue @vitejs/plugin-vue -D 安装 Vite TypeScript 及 Vue3,并且添加我们需要的 scripts 命令:

{
  "name": "starter-lib-vue3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    // 将命令添加到 scripts 中
    "dev": "vite build --watch",
    "build": "vite build",
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

同时,需要将 Vue3 添加到 peerDependencies 中:

"peerDependencies": {
    "vue": "^3.2.0"
 },

创建必要的目录结构:

├── src/
│   ├── components/ # 组件目录
│   └── index.ts # 入口文件
├── vite.config.ts
├── tsconfig.json
└── package.json

tsconfig.json 可以从如下地址复制:github.com/starter-col…

接下来,我们配置 vite.config.ts

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

export default defineConfig({
  plugins: [vue()],
  build: {
    lib: {
      // 入口文件,指向你的组件库的主文件
      entry: './src/index.ts',
      // 库的名称
      name: 'StarterLibVue3',
      // 导出的模块格式
      formats: ['es', 'umd', 'cjs'],
      // 打包后文件名
      fileName: format => `index.${format}.js`,
    },
    rollupOptions: {
      // 确保外部化处理不需要打包的依赖
      external: ['vue'], // 排除 Vue
      output: {
        // 在 UMD 模式下为外部化的依赖提供全局变量
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
})

至此,你的开发环境已经搭建完成。

2. 搭建在线文档

因为已经使用 Vite 进行组件库的打包,所以我们统一技术栈,使用 Vitepress 搭建在线文档。

如果你对 Vitepress 还不熟悉,强烈推荐看我之前写过的文章 《年终提效 & 项目包装必备,VitePress 保姆级指南,内含国际化、组件和代码自动展示》

运行 npx vitepress init 初始化 Vitepress 功能。

package.json 添加运行命令(如果上面自动生成命令的话,跳过该步骤即可)

"scripts": {
  // 其他命令
  // ...
  "docs:dev": "vitepress dev docs",
  "docs:build": "pnpm build && vitepress build docs",
  "docs:preview": "vitepress preview docs",
}

现在我们运行 pnpm run docs:dev 即可看到我们安装好的 Vitepress 文档。

你可以通过编写 MD 文件及 .vitepress 下面布局配置书写你的组件库文档。

对于如何在文档中展示组件和示例代码,本文将在 五、组件的在线文档及代码片段 章节介绍。

3. 打包 Vue3 单组件

我们在 /src/components 下新建一个名为 SayHello.vue 的组件(当然,你也可以用其他命名)。

目录结构结果如下:

SayHello.vue 组件:

<script lang="ts" setup>
defineOptions({
  name: 'StSayHello',
})

const { name } = defineProps<{
  name: string
}>()

function sayHello() {
  // eslint-disable-next-line no-alert
  alert(`Hello, ${name}!`)
}
</script>

<template>
  <button class="starter-lib-vue3-say-hello" @click="sayHello()">
    Say, hi!
  </button>
</template>

<style>
@import url('./style.css');
</style>

style.css 文件,我简单写了下 button 样式:

.starter-lib-vue3-say-hello{
  background: #42b883;
  color: white;
  padding: 8px 20px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  margin: 4px 2px;
  cursor: pointer;
  border-radius: 6px;
}

/src/components/say-hello/index.ts 文件中导出写好的组件:

import SayHello from './SayHello.vue'

export const StSayHello = SayHello

export default StSayHello

同时,在 /src/index.ts 入口文件中导出该组件:

import StSayHello from './components/say-hello'

export {
  StSayHello,
}

现在我们运行 npx vite build 即可看到打包的结果:

Vite 为我们输出了三种不同格式的产物,分别是 **.cjs.js**.esm.js**.umd.js, 同时还输出了一个 css 样式文件。

当我们要使用组件库的产物或者将包发布到 npm 时,我们需要为 package.json 添加正确的配置,确保依赖能够正常导入:

{
  // 你的组件库名称
  "name": "starter-lib-vue3",
  "type": "module",
  "version": "0.0.0",
  "exports": {
    ".": {
      "import": "./dist/index.es.js",
      "require": "./dist/index.cjs.js"
    },
    "./*": "./*"
  },
  "main": "./dist/index.umd.js",
  "module": "./dist/index.es.js",
  "files": ["dist"],
  // 之前添加过的其他配置
  // ...
}

4. 本地调试打包后的产物

现在已经成功打包出来开发的组件,但是我们不能每次调试都发布到 npm,这样会非常麻烦,也会增加很多没有意义的版本发布。

这就会用到 pnpm link 这个命令。

官方文档的介绍:pnpm.io/zh/cli/link

我们创建一个新的 Vite + Vue3 项目。运行 npx degit starter-collective/starter-vite-vue3 starter-vite-vue3 即可下载作者搭建的模板。

当然,你也可以使用使用 Vite 创建一个空的项目,运行 npm create vite@latest,根据步骤进行创建,然后运行 pnpm install 安装依赖。

接下来,我们在创建的 Vite Demo 项目中运行 pnpm link ../starter-lib-vue3npm link 后面是你自己组件库的路径)命令即可关联到组件库 dist 目录。

<route lang="json">
{
  "name": "index",
  "meta": {
    "layout": "page"
  }
}
</route>

<script lang="ts" setup>
import { StSayHello } from 'starter-lib-vue3'
import 'starter-lib-vue3/dist/starter-lib-vue3.css'
</script>

<template>
  <TheCard my-5 flex="~ items-center justify-center gap-2 wrap">
    <StSayHello name="world" />
  </TheCard>
</template>

运行效果如下:

到这里,恭喜你,一个最简版本的组件库就完成了 :D

如果想要解锁全部组件库的功能,如 Volar 提示、类型声明、TreeShaking 及 Vite 自动导入等,我们接着往下看。

三、深入组件库核心

1. 类型文件自动生成和导出

你可能注意到了,像 Element Plus 或者 Naive UI 等主流组件库的构建产物,都有 *.d.ts 文件,用于声明组件的参数类型和 API 类型。

要想实现这个功能,非常简单,我们直接安装 vite-plugin-dts 插件:

pnpm add vite-plugin-dts -D

将插件在 vite.config.ts 中导入:

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

export default defineConfig({
  plugins: [
    vue(),
    dts({
      tsconfigPath: 'tsconfig.json',
      outDir: './dist',
      entryRoot: './src',
      exclude: ['node_modules', 'vite.config.ts'],
    }),
  ],
  // 其他配置
  // ...
})

接下来我们运行打包命令,可以看到输出产物有了 *.d.ts 文件:

还需要向 package.json 中加入类型路径声明:

  // 其他配置
  // ...
  "exports": {
    ".": {
      // 类型声明
      "types": "./dist/index.d.ts",
      "import": "./dist/index.es.js",
      "require": "./dist/index.cjs.js"
    },
    "./*": "./*"
  },
  "main": "./dist/index.umd.js",
  "module": "./dist/index.es.js",
  // 类型声明
  "types": "./dist/index.d.ts",

现在你的 npm 包就可以被正确的识别 TypeScript 类型了。如下图所示:

2. Vite 库模式之 Rollup 扩展

Vite 构建生产环境时是使用 Rollup 进行的编译,并且内置了 Tree Shaking(什么是 Tree Shaking? )优化,所以可以直接在 vite.config.ts 文件中编写 Rollup 配置。

对于 Rollup 的配置,这里不会讨论太多,我们只关注 output 配置部分,先上最优配置结果,然后再拆解为什么要这么配置:

// 其他 vite 配置
// ...
build: {
  // 清空输出目录
  emptyOutDir: true,
  // 开启最小化混淆
  minify: true,
  // css 文件切割
  cssCodeSplit: true,
  lib: {
    entry: 'src/index.ts',
    name: 'StarterLibVue3',
    fileName: format => `index.${format}.js`,
  },
  rollupOptions: {
    external: [
     'vue',
    ],
    output: [
      {
        // es 产物配置
        format: 'es',
        entryFileNames: '[name].js',
        exports: 'named',
        preserveModules: true,
        preserveModulesRoot: 'src',
        dir: './dist/es',
        assetFileNames: (assetInfo) => {
          if (assetInfo.names && assetInfo.names.some(name => name.endsWith('.css'))) {
            return path.join(path.dirname(assetInfo.names[0]), 'style.css')
          }
          return '[name].[ext]'
        },
      },
      {
        // cjs 产物配置
        format: 'cjs',
        entryFileNames: '[name].js',
        exports: 'named',
        preserveModules: true,
        preserveModulesRoot: 'src',
        dir: './dist/lib',
        assetFileNames: (assetInfo) => {
          if (assetInfo.names && assetInfo.names.some(name => name.endsWith('.css'))) {
            return path.join(path.dirname(assetInfo.names[0]), 'style.css')
          }
          return '[name].[ext]'
        },
      },
      {
        // umd 产物配置
        format: 'umd',
        entryFileNames: 'index.js',
        exports: 'named',
        name: 'StarterLibVue3',
        dir: './dist/umd',
        globals: {
          vue: 'Vue',
        },
      },
    ],
  },
}

rollupOptions.output 选项默认是一个对象,也可以是一个对象数组,类型为:OutputOptions | OutputOptions[]

类型详见:cn.rollupjs.org/javascript-…

我们仿照主流组件库,也提供三种格式的产物:es、cjs、umd。将 rollupOptions.output 选项设置为一个数组,分别编写对应三种产物的配置。

  • 其中,preserveModules: truepreserveModulesRoot: 'src' 会开启结构化构建,即你的源码目录结构是什么样,打包后就是什么结构,如下图所示:

  • 使用 dir 分别配置不同的产物目录,进行区分,如 ./dist/es./dist/lib./dist/umd,如 Element Plus 的产物结构:

  • 因为 Vite 在配置了 cssCodeSplit: true 后会将默认的打包为一个样式文件切割成多个,并且会按照组件名称进行重命名。我们想要其在组件目录下使用相同的命令 style.css。可以通过配置 assetFileNames 重命名切割后的样式文件。结果如下图所示:

由于拆分后,原先的 vite-plugin-dts 插件只能生成一套类型。你可以考虑设置一个公共的 dist/types 目录,用于类型输出,也可以分别针对 CJS 和 ESM 自动输出类型声明文件。这里我们考虑后者方案,配置如下:

import path from 'node:path'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'

export default defineConfig({
  plugins: [
    vue(),
    dts({
      tsconfigPath: 'tsconfig.json',
      outDir: './dist/es',
      entryRoot: './src',
      exclude: ['node_modules', 'tests', 'vite.config.ts'],
    }),
    dts({
      tsconfigPath: 'tsconfig.json',
      outDir: './dist/lib',
      entryRoot: './src',
      exclude: ['node_modules', 'tests', 'vite.config.ts'],
    }),
  ],
})

构建结果如下:

可以看到,同时在 libes 目录下生成了 *.d.ts 文件。最后 package.json 也需要同步修改配置:

{
    // 其他配置
    // ...
    "exports": {
        ".": {
          // 默认使用 es 目录下的类型文件
          "types": "./dist/es/index.d.ts",
          "import": "./dist/es/index.js",
          "require": "./dist/lib/index.js"
        },
      },
      "main": "dist/lib/index.js",
      "module": "dist/es/index.js",
      // 默认使用 es 目录下的类型文件
      "types": "dist/es/index.d.ts",
}

3. 全局注册组件库

按照 Vue 官方文档,注册一个全局组件,我们可以使用 Vue 应用实例的 .component() 方法,让组件在当前 Vue 应用中全局可用。

import { createApp } from 'vue'

const app = createApp({})

app.component(
  // 注册的名字
  'MyComponent',
  // 组件的实现
  {
    /* ... */
  }
)

但是对于组件库来说,会有很多的组件需要注册。所以我们将组件导出为一个数组,将这个数组进行循环注册即可。

首先,我们在 /src 目录下新建一个 components.ts 文件:

import type { Plugin } from 'vue'
import StSayHello from './say-hello'

export * from './say-hello'

export const components = [
  StSayHello,
] as Plugin[]

export default components

然后我们写一个工具函数进行批量注册组件即可:

作者是在 /src 目录下创建了一个 /utils 目录用于存的工具函数。

import type { App, Plugin } from 'vue'
import { version } from '../../package.json'

export const INSTALLED_KEY = Symbol('INSTALLED_KEY')

declare module 'vue' {
  interface App {
    [INSTALLED_KEY]?: boolean
  }
}

export function createInstaller(components: Plugin[] = []): { install: (app: App) => void, version: string } {
  const install = (app: App): void => {
    if (app[INSTALLED_KEY])
      return

    app[INSTALLED_KEY] = true
    components.forEach(c => app.use(c))
  }

  return {
    install,
    version,
  }
}

在组件库入库文件中创建安装函数,并且默认导出即可:

import { components } from './components'
import { createInstaller } from './utils/installer'

export * from './components'

const installer = createInstaller(components)

export const install = installer.install
export const version = installer.version

export default installer

现在我们可以使用全局注册组件了:

// main.ts
import StarterLibVue3 from 'starter-lib-vue3'
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.use(StarterLibVue3)
app.mount('#app')

但是你会发现我们的样式依然需要手动导入,Vite 构建的产物并没有一个全局的样式文件。

所以需要一个全局的样式文件,我们接着往下看。

4. 全局样式引入

全局注册组件的同时需要全局引入样式,但是Vite 在配置了 cssCodeSplit: true 后会自动切割样式,只能按需引入组件的样式。如果关闭 cssCodeSplit: true 则不能实现按需引入。

这里经过我的几个不同方案试验,最终可以通过一个插件实现合并所有的样式文件。

插件的原理就是扫描 /src 目录下的样式文件进行解析合并,具体可以查看如下链接:

github.com/kieranwv/vi…

当然了,如果你有更简单,学习成本更低的方式同时实现 “样式切割和样式整合”,欢迎在评论区交流和在 GitHub 提交 PR :D

运行 pnpm add vite-plugin-bundle-styles -D , 按照下面进行配置:

import { viteBundleStyles } from 'vite-plugin-bundle-styles'

export default defineConfig({
  // 其他配置
  // ...
  plugins: [
    // 其他插件
    // ...
    viteBundleStyles({
      target: './src',
    }),
  ],
})

运行 Vite 打包命令可以得到如下结果:

修改 package.json 的配置,实现 styles.css 样式路径的正确匹配:

{
  // 其他配置
  // ...
  "exports": {
    ".": {
      "types": "./dist/es/index.d.ts",
      "import": "./dist/es/index.js",
      "require": "./dist/lib/index.js"
    },
    "./*": "./*",
    "./style": "./dist/es/styles.css"
  }
}

现在我们可以使用全局注册组件和样式引入了:

// main.ts
import StarterLibVue3 from 'starter-lib-vue3'
import { createApp } from 'vue'
import App from './App.vue'
import 'starter-lib-vue3/style'

const app = createApp(App)

app.use(StarterLibVue3)
app.mount('#app')
<!-- App.vue -->
<template>
  <StSayHello name="Kieran" />
</template>

5. Vite 自动导入插件适配

当我们需要引入大量组件的时候,挨个手动导入会非常费时费力。所有我们提供一个插件用于组件和样式文件自动导入。

类似 Element Plus 使用的自动导入:

我们在组件库项目中运行 pnpm add unplugin-vue-components -D 安装插件。

接下来在 /src 目录下新建一个 resolver.ts 文件,并且在 /src/index.ts 中导出:

import type { ComponentResolver } from 'unplugin-vue-components'
// 大小写格式化函数
// https://github.com/kieranwv/utils/blob/main/src/format.ts
import { toLowerCase } from '@kieranwv/utils'

export function StarterLibVue3Resolver(): ComponentResolver {
  return {
    type: 'component',
    resolve: (name: string) => {
      if (name.match(/^St[A-Z]/)) {
        return {
          name,
          from: 'starter-lib-vue3',
          // 
          sideEffects: [
            `starter-lib-vue3/dist/es/${toLowerCase(name.replace('St', ''))}/style.css`,
          ],
        }
      }
    },
  }
}

同时,还需要在 package.json 中补充样式文件声明:

{
  // ...
  "sideEffects": [
    "dist/**/*.css"
  ],
}

在使用组件库时,你需要安装unplugin-vue-components 和 unplugin-auto-import这两款插件:

pnpm add unplugin-vue-components unplugin-auto-import -D

然后把下列代码插入到你项目的 Vite 的配置文件中:

// vite.config.ts
import { StarterLibVue3Resolver } from 'starter-lib-vue3'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  // ...
  plugins: [
    // ...
    AutoImport({
      resolvers: [StarterLibVue3Resolver()],
    }),
    Components({
      resolvers: [StarterLibVue3Resolver()],
    }),
  ],
})

现在你可以在 SFC 文件中直接使用 starter-lib-vue3 的组件,并且其样式也是自动化的导入。

<script>
// 无需手动引入 :P
// import { StSayHello } from 'starter-lib-vue3'
// import 'starter-lib-vue3/dist/es/say-hello/style.css'
</script>

<template>
  <StSayHello name="Kieran" />
</template>

6. Volar 代码提示

对于 Vue3 组件库,我们内置了 Volar 的支持,通过以下简单的配置即可实现。

/src 目录下新建一个 volar.d.ts 文件并且声明类型:

declare module 'vue' {
  export interface GlobalComponents {
    StSayHello: typeof import('starter-lib-vue3')['StSayHello']
  }
}

export { }

运行 pnpm add vite-plugin-static-copy -D 安装插件,通过该插件在打包时将文件从 /src 目录拷贝到 /dist 目录下:

// ...
import { viteStaticCopy } from 'vite-plugin-static-copy'

export default defineConfig({
  // 其他配置
  // ...
  plugins: [
      // 其他配置
      // ...
      // https://github.com/sapphi-red/vite-plugin-static-copy
      viteStaticCopy({
        targets: [
           { src: './src/volar.d.ts', dest: './' },
        ],
      hook: 'writeBundle',
    }),
  ]
})

然后在 package.json 中声明文件位置即可:

{
  // ...
  "exports": {
    // ...
    "./volar": "./dist/volar.d.ts",
  },
}

使用 Volar 时,我们需要配置项目的 tsconfig.json 文件,以此正确的开启 Volar 支持:

// tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": ["starter-lib-vue3/volar"]
  }
}

使用效果如下:

四、组件单元测试

对于库来说,单元测试是必不可少的。这一章,为你讲解如何在组件库中集成 Vitest 以及编写你的第一个单元测试。

Vitest 文档地址:cn.vitest.dev/

1. 集成 Vitest

运行如下命令安装 Vitest:

pnpm add vitest -D

由于我们组件库已经是使用 Vite 进行构建的,所以我们不需要额外的 Vitest 配置文件,直接在 Vite 中配置即可。

/// <reference types="vitest/config" />

import { defineConfig } from 'vite'

export default defineConfig({
  // 其他配置
  // ...
  // https://github.com/vitest-dev/vitest
  test: {
    include: ['tests/**/*'],
    environment: 'jsdom',
  },
})

此外,你需要留意三斜杠的配置:

至此,Vitest 的配置流程就结束了,可以说是非常的简单了 :D 接下来我们开始编写测试用例。

2. 编写测试用例

我们在项目根目录下新建一个 test 目录,并且新建一个 say-hello.test.ts 测试文件:

作者直接让 Copilot 生成了一个简单的测试用例。因为本章重点是在组件库中集成 Vtest,所以不会展开讲解 Vitest,如果需要,可以查阅文档或者在评论区留言,后面我会单独出一篇文章讲解 Vitest

import { mount } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
import SayHello from '../src/say-hello/SayHello.vue'

describe('test for SayHello.vue', () => {
  it('renders a button', () => {
    const wrapper = mount(SayHello, {
      props: {
        name: 'World',
      },
    })
    expect(wrapper.find('button').exists()).toBe(true)
  })

  it('calls sayHello method when button is clicked', async () => {
    const wrapper = mount(SayHello, {
      props: {
        name: 'World',
      },
    })
    window.alert = vi.fn()
    await wrapper.find('button').trigger('click')
    expect(window.alert).toHaveBeenCalledWith('Hello, World!')
  })
})

  • 测试用例有两个,一个是验证组件是否能正确挂载,另一个是验证组件的 name 属性是否能正常使用。

  • 我们发现这个测试用例里依赖了一个 @vue/test-utils 的库,这个库是用于 Vue 组件的单元测试工具库,我们运行 pnpm add @vue/test-utils -D 来安装一下它。

  • vi 是 Vitest 提供的辅助工具。

最后我们运行 npx vitest 即可显示测试运行结果:

3. 自动化测试

我们在对组件配置了测试用例后,我们不想每次都需要手动运行测试命令。需要让它在代码提交时自动运行测试命令,确保每次提交的代码都是通过测试可正确运行的。

首先运行 pnpm add simple-git-hooks -D 安装 simple-git-hooks

simple-git-hooks 是一个适用于小型项目的简单 git hooks 管理器。

github.com/toplenboren…

接下来为 package.json 添加如下配置:

{
  // 其他配置
  // ...
  "scripts":{
    // 其他配置
    // ...
    "prepare": "simple-git-hooks",
    "test": "vitest"
  },
  "simple-git-hooks": {
    "pre-commit": "pnpm test"
  },
}

我们重新运行一下 pnpm install 即可使其生效。然后我们每次进行 Commit 提交时都会触发单元测试。

当然也可以将单元测试放到 GitHub CI/CD 或者 GitLab Runner 中执行。这里不作为重点,就不展开讲了,如果需要可以在评论区留言,我后面单独出一篇文章讲解。

五、在线文档及代码片段展示

我们按照文章 《年终提效 & 项目包装必备,VitePress 保姆级指南,内含国际化、组件和代码自动展示》 中的 ## 六、使用插件和自动化展示 Vue 组件 步骤完成示例组件的导入。

六、npm 发布及版本管理

1. npm 发布包

在将组件库发布到 npm 之前,有几个需要配置的参数:

{
  // package.json
  // 你的 npm 包名
  "name": "",
  // 默认 ES Module 即可
  "type": "module",
  // 版本号
  "version": "0.1.0",
  // 你的 npm 包描述
  "description": "",
  // 作者信息
  "author": "",
  // 许可证
  "license": "MIT",
  // npm 包网站
  "homepage": "",
  // npm 包仓库地址
  "repository": {
    "type": "",
    "url": ""
  },
  // bug 提交地址
  "bugs": {
    "url": ""
  },
  // npm 包关键字,与检索有关
  "keywords": [],
  // 要发布的文件列表,其中 README 和 package.json 是默认发布的,不需要显示声明。
  "files": [
    "dist"
  ],
  // 其他配置在本文章都介绍过了
  // ...
}

作者完整的配置文件:github.com/starter-col…

接下来,我们正式开始发布到 npm。

需要你拥有一个 npm 账号,注册步骤安装 npm 官方网站进行即可。

www.npmjs.com/

我们在项目根目录下运行打包命令,完成最新的代码构建。然后运行 npm login 按照命令行提供的步骤(因为作者绑定了 Authenticator,所以登录步骤会不太一样),登录我们的 npm 账号:

登录成功,我们运行 npm publish 即可将包发布到 npm 上:

发布成功后,在 npm 网站上就可以看到你发布的包了:

2. 版本管理

对于库来说,一个合适的版本管理工具尤为重要,可以搭配命令行快捷切换版本号,作者使用的是 bumpp

运行 pnpm add bumpp 安装依赖。

github.com/antfu-colle…

将打包命令、版本控制命令集成到 scripts 中:

{
  // 其他配置
  // ...
  {
    "scripts":{
      // ...
      "release": "bumpp && pnpm build && pnpm publish"
    }
  }
}

接下来我们运行 release 即可:

同时, Bumpp 也可以与 Changelog 搭配使用,后面我会单独出一篇文章介绍具体用法。

最后,Bumpp 设置的 tag 你可以在仓库中看到:

总结

本文章综合介绍了如何使用 Vite 完整搞定组件库的开发。同时介绍了在线文档、单元测试及版本发布等内容。大家有任何问题,欢迎在评论区留言。

如果项目对你有帮助,欢迎点个 Star :D