各位观众老爷,晚上好! 今天咱们来聊聊如何用 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 组件库! 咱们下期再见!