各位观众老爷,晚上好! 今天咱们来聊聊如何用 Vite 的 lib 模式,把你的 Vue 组件库打造成“变形金刚”,想变啥样就变啥样,ESM、UMD、CommonJS,统统不在话下!
开场白:组件库的“格式化”需求
话说咱们写 Vue 组件,写得那叫一个行云流水,但写完之后,总得想着怎么把它分享给别人用吧? 这就涉及到组件库的打包和发布问题。 不同的项目,使用的模块化规范可能不一样,有的用 ESM,有的用 CommonJS,还有的用 UMD。 为了让你的组件库能适应各种环境,最好能打包成多种格式。
Vite 的 lib 模式,就是专门用来干这个的! 它能帮你把你的组件库打包成各种你想要的格式,简直是组件库开发者的福音。
第一幕:Vite lib 模式初体验
首先,咱们得有个 Vue 组件库的雏形。 假设我们有个非常简单的组件,就叫 MyButton.vue,内容如下:
<template>
<button @click="handleClick">{{ label }}</button>
</template>
<script>
export default {
name: 'MyButton',
props: {
label: {
type: String,
default: 'Click Me!'
}
},
methods: {
handleClick() {
alert('Button clicked!');
}
}
};
</script>
接下来,咱们创建一个 vite.config.js 文件,这是 Vite 的配置文件,也是咱们施展魔法的地方。
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
build: {
lib: {
entry: 'src/MyButton.vue', // 组件库的入口文件
name: 'MyButton', // 打包后的全局变量名 (UMD 模式下)
fileName: (format) => `my-button.${format}.js` // 输出文件名
},
rollupOptions: {
// 确保外部化处理那些你不想打包进库的依赖
external: ['vue'],
output: {
// 在 UMD 构建模式下,需要配置全局变量来使用外部依赖
globals: {
vue: 'Vue'
}
}
}
}
});
解释一下几个关键配置:
lib.entry: 指定组件库的入口文件,这里是src/MyButton.vue。lib.name: 指定打包后的全局变量名,在 UMD 模式下,会把组件库挂载到这个全局变量上,这里是MyButton。lib.fileName: 指定输出文件名,可以是一个函数,根据format参数(ESM, UMD, CommonJS 等)动态生成文件名。rollupOptions.external: 指定需要外部化的依赖,也就是说,这些依赖不会被打包进组件库,而是由用户在项目里提供。 像 Vue 这种基础依赖,一般都应该外部化。rollupOptions.output.globals: 在 UMD 模式下,需要配置全局变量来使用外部依赖。 比如,我们把vue映射到全局变量Vue上,这样 UMD 版本的组件库就可以直接使用Vue了。
配置好了之后,就可以运行 vite build 命令来打包组件库了。 打包完成后,会在 dist 目录下生成一个 my-button.es.js 文件 (ESM 格式) 和一个 my-button.umd.js 文件(UMD格式)。
第二幕:多格式齐发,配置升级
上面的例子只打包了 ESM 和 UMD 两种格式。 如果我们还想要 CommonJS 格式,怎么办呢? 别慌,Vite 早就为我们准备好了!
只需要修改 vite.config.js 文件,把 lib.formats 选项加上:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
build: {
lib: {
entry: 'src/MyButton.vue',
name: 'MyButton',
formats: ['es', 'umd', 'cjs'], // 指定要打包的格式
fileName: (format) => `my-button.${format}.js`
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
}
}
}
}
});
在 lib 选项中添加 formats: ['es', 'umd', 'cjs'] 就可以了。 这样,Vite 就会打包出 ESM、UMD 和 CommonJS 三种格式的文件。
运行 vite build 命令,你会在 dist 目录下看到 my-button.es.js、my-button.umd.js 和 my-button.cjs.js 三个文件。
第三幕:高级定制,灵活应变
Vite 的 lib 模式还提供了很多高级定制选项,可以让你更灵活地控制打包过程。
-
lib.entry可以是多个入口文件如果你的组件库由多个组件组成,可以把
lib.entry设置为一个对象,指定多个入口文件。build: { lib: { entry: { MyButton: 'src/MyButton.vue', MyInput: 'src/MyInput.vue' }, name: 'MyComponentLib', // 打包后的全局变量名 formats: ['es', 'umd'], fileName: (format, name) => `${name}.${format}.js` // 根据入口文件名生成输出文件名 }, rollupOptions: { external: ['vue'], output: { globals: { vue: 'Vue' } } } }这样,Vite 就会分别打包
MyButton.vue和MyInput.vue,生成MyButton.es.js、MyButton.umd.js、MyInput.es.js和MyInput.umd.js四个文件。 注意fileName的写法,name 参数会被传入文件名. -
build.outDir指定输出目录默认情况下,Vite 会把打包后的文件输出到
dist目录下。 如果你想修改输出目录,可以使用build.outDir选项。build: { outDir: 'lib', // 指定输出目录为 lib lib: { entry: 'src/MyButton.vue', name: 'MyButton', formats: ['es', 'umd', 'cjs'], fileName: (format) => `my-button.${format}.js` }, rollupOptions: { external: ['vue'], output: { globals: { vue: 'Vue' } } } }这样,打包后的文件就会输出到
lib目录下。 -
build.minify控制是否压缩代码默认情况下,Vite 会对打包后的代码进行压缩。 如果你想关闭代码压缩,可以设置
build.minify为false。build: { minify: false, // 关闭代码压缩 lib: { entry: 'src/MyButton.vue', name: 'MyButton', formats: ['es', 'umd', 'cjs'], fileName: (format) => `my-button.${format}.js` }, rollupOptions: { external: ['vue'], output: { globals: { vue: 'Vue' } } } }关闭代码压缩可以提高打包速度,方便调试。
-
build.rollupOptions.output.exports控制 CommonJS 导出方式CommonJS 格式的导出方式有两种:
named和default。 默认情况下,Vite 使用named导出,也就是把组件库的每个组件都作为具名导出。 如果你想使用default导出,可以设置build.rollupOptions.output.exports为default。build: { lib: { entry: 'src/MyButton.vue', name: 'MyButton', formats: ['es', 'umd', 'cjs'], fileName: (format) => `my-button.${format}.js` }, rollupOptions: { external: ['vue'], output: { exports: 'default', // 使用 default 导出 globals: { vue: 'Vue' } } } }使用
default导出后,在 CommonJS 环境下,需要使用require('my-button.cjs.js').default来引入组件。
第四幕:进阶技巧,玩转组件库
除了上面的基本配置,还有一些进阶技巧可以帮助你更好地构建组件库。
-
使用
vite-plugin-dts生成 TypeScript 类型声明文件如果你的组件库是用 TypeScript 写的,可以使用
vite-plugin-dts插件来生成类型声明文件 (.d.ts)。 这样,其他开发者在使用你的组件库时,就可以获得更好的类型提示。首先,安装
vite-plugin-dts插件:npm install vite-plugin-dts --save-dev然后,在
vite.config.js文件中配置插件:import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import dts from 'vite-plugin-dts'; export default defineConfig({ plugins: [vue(), dts()], build: { lib: { entry: 'src/MyButton.vue', name: 'MyButton', formats: ['es', 'umd', 'cjs'], fileName: (format) => `my-button.${format}.js` }, rollupOptions: { external: ['vue'], output: { globals: { vue: 'Vue' } } } } });运行
vite build命令后,会在dist目录下生成my-button.d.ts文件。 -
使用
vue-demi兼容 Vue 2 和 Vue 3如果你的组件库需要同时兼容 Vue 2 和 Vue 3,可以使用
vue-demi库。vue-demi可以让你在同一份代码中编写 Vue 2 和 Vue 3 的兼容代码。首先,安装
vue-demi库:npm install vue-demi --save-dev然后,在你的组件代码中使用
vue-demi提供的 API。 例如,可以使用defineComponent替代Vue.extend,使用computed替代Vue.computed等。<template> <button @click="handleClick">{{ label }}</button> </template> <script> import { defineComponent } from 'vue-demi'; export default defineComponent({ name: 'MyButton', props: { label: { type: String, default: 'Click Me!' } }, methods: { handleClick() { alert('Button clicked!'); } } }); </script>最后,在
vite.config.js文件中配置vue-demi:import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { resolve } from 'path'; export default defineConfig({ plugins: [vue()], resolve: { alias: { 'vue': 'vue-demi' } }, build: { lib: { entry: 'src/MyButton.vue', name: 'MyButton', formats: ['es', 'umd', 'cjs'], fileName: (format) => `my-button.${format}.js` }, rollupOptions: { external: ['vue'], output: { globals: { vue: 'Vue' } } } } });这样,你的组件库就可以同时在 Vue 2 和 Vue 3 项目中使用了。
第五幕:实战演练,组件库打包流程
为了让大家更好地掌握 Vite lib 模式的使用,咱们来模拟一个完整的组件库打包流程。
-
创建组件库项目
mkdir my-component-lib cd my-component-lib npm init -y npm install vue @vitejs/plugin-vue vite -D -
创建组件
创建
src/MyButton.vue文件,内容如下:<template> <button @click="handleClick">{{ label }}</button> </template> <script> export default { name: 'MyButton', props: { label: { type: String, default: 'Click Me!' } }, methods: { handleClick() { alert('Button clicked!'); } } }; </script> -
创建
vite.config.js文件创建
vite.config.js文件,内容如下:import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ plugins: [vue()], build: { lib: { entry: 'src/MyButton.vue', name: 'MyButton', formats: ['es', 'umd', 'cjs'], fileName: (format) => `my-button.${format}.js` }, rollupOptions: { external: ['vue'], output: { globals: { vue: 'Vue' } } } } }); -
修改
package.json文件在
package.json文件中添加build命令:{ "name": "my-component-lib", "version": "1.0.0", "description": "", "main": "dist/my-button.umd.js", // 指定 CommonJS 格式的入口文件 "module": "dist/my-button.es.js", // 指定 ESM 格式的入口文件 "exports": { // 定义不同环境下的入口文件 ".": { "import": "./dist/my-button.es.js", "require": "./dist/my-button.cjs.js" } }, "scripts": { "build": "vite build" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "@vitejs/plugin-vue": "^4.5.2", "vite": "^5.0.8", "vue": "^3.3.11" } }重要说明:
main字段: 指定 CommonJS 格式的入口文件。 老项目可能会使用这个字段。module字段: 指定 ESM 格式的入口文件。 一些打包工具会优先使用这个字段。exports字段: 强烈推荐使用。 它允许你根据不同的环境(import/require)指定不同的入口文件,提供更精确的模块化支持。.表示默认入口,可以根据import和require分别指定 ESM 和 CommonJS 的入口。
-
运行
build命令npm run build打包完成后,会在
dist目录下生成my-button.es.js、my-button.umd.js和my-button.cjs.js三个文件。 -
发布组件库
npm publish发布成功后,其他开发者就可以在自己的项目中使用你的组件库了。
总结:Vite lib 模式的优势
Vite 的 lib 模式为组件库开发者带来了诸多便利:
- 配置简单: 只需要简单的配置,就可以打包出多种格式的组件库。
- 速度快: 基于 Rollup 的打包引擎,速度非常快。
- 灵活定制: 提供了很多高级定制选项,可以满足各种需求。
- 生态完善: Vite 生态中有丰富的插件,可以帮助你更好地构建组件库。
表格总结
| 配置项 | 描述 | 示例 |
|---|---|---|
build.lib.entry |
组件库的入口文件,可以是单个文件或多个文件的对象。 | 'src/MyButton.vue' 或 { MyButton: 'src/MyButton.vue', MyInput: 'src/MyInput.vue' } |
build.lib.name |
打包后的全局变量名 (UMD 模式下)。 | 'MyComponentLib' |
build.lib.formats |
指定要打包的格式,例如 'es', 'umd', 'cjs'。 |
['es', 'umd', 'cjs'] |
build.lib.fileName |
输出文件名,可以是一个函数,根据 format 和 name 参数动态生成文件名。 |
(format) => my-button.${format}.js`或(format, name) => `${name}.${format}.js“ |
build.outDir |
指定输出目录,默认为 dist。 |
'lib' |
build.minify |
控制是否压缩代码,默认为 true。 |
false |
build.rollupOptions.external |
指定需要外部化的依赖,这些依赖不会被打包进组件库。 | ['vue'] |
build.rollupOptions.output.globals |
在 UMD 模式下,需要配置全局变量来使用外部依赖。 | { vue: 'Vue' } |
build.rollupOptions.output.exports |
控制 CommonJS 导出方式,可以是 'named' 或 'default'。 |
'default' |
好了,今天的讲座就到这里。 希望大家能够掌握 Vite lib 模式的使用,打造出高质量、多格式的 Vue 组件库! 咱们下期再见!