WHAT - 组件库单入口打包和多入口打包
文章目录
- 一、什么是单入口与多入口打包?
- 单入口打包(Single Entry Build)
- 多入口打包(Multi Entry Build)
- 二、两种方式对比
- 三、构建方式实践(以 Vite + Rollup 为例)
- 单入口打包实践
- 项目结构
- index.ts 示例
- vite.config.ts 配置
- 多入口打包实践
- 项目结构
- 每个组件都有一个独立入口
- vite.config.ts 配置
- 四、额外建议
- 类型声明
- 混合模式
- 五、NPM 发布结构建议
- 总结推荐
在手写组件库时,选择“单入口打包”还是“多入口打包”是一个非常重要的架构和构建决策。
下面我将从概念、优缺点、适用场景、构建方式(以 Vite/Rollup 为主)、实践建议等方面为你全面展开介绍。
一、什么是单入口与多入口打包?
单入口打包(Single Entry Build)
-
所有组件通过一个统一入口(如
index.ts
)导出并打包为一个文件(或多个格式,如 ESM/CJS)。 -
使用方式:
import { Button, Modal } from 'my-ui-lib';
多入口打包(Multi Entry Build)
-
每个组件都有独立的入口文件(如
button/index.ts
),可以单独按需打包。 -
使用方式:
import Button from 'my-ui-lib/button'; import Modal from 'my-ui-lib/modal';
二、两种方式对比
项目 | 单入口 | 多入口 |
---|---|---|
打包产物体积 | 大,包含所有组件 | 小,可按需引入 |
Tree-shaking | 支持,但依赖使用者工具配置 | 更加彻底地按需引入 |
用户使用体验 | 更简单,一次性引入 | 更灵活,适合大型项目 |
维护成本 | 低,只有一个入口文件 | 高,每个组件需独立配置入口和构建 |
编译速度 | 快 | 慢(构建多个入口) |
推荐场景 | 小型组件库 | 中大型组件库,强调性能 |
三、构建方式实践(以 Vite + Rollup 为例)
单入口打包实践
项目结构
src/
├── components/
│ ├── Button.tsx
│ └── Modal.tsx
├── index.ts
index.ts 示例
export { default as Button } from './components/Button';
export { default as Modal } from './components/Modal';
vite.config.ts 配置
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';export default defineConfig({build: {lib: {entry: './src/index.ts',name: 'MyUILib',fileName: 'my-ui-lib',},rollupOptions: {external: ['react', 'react-dom'],output: {globals: {react: 'React','react-dom': 'ReactDOM',},},},},plugins: [dts()],
});
多入口打包实践
项目结构
src/
├── button/
│ ├── index.ts
│ └── Button.tsx
├── modal/
│ ├── index.ts
│ └── Modal.tsx
每个组件都有一个独立入口
src/button/index.ts
export { default } from './Button';
vite.config.ts 配置
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
import path from 'path';
import fs from 'fs';// 自动扫描所有组件目录
const entryPoints = fs.readdirSync(path.resolve(__dirname, 'src')).reduce((acc, dir) => {const fullDir = path.resolve(__dirname, 'src', dir);const entryFile = path.resolve(fullDir, 'index.ts');if (fs.existsSync(entryFile)) {acc[dir] = entryFile;}return acc;
}, {} as Record<string, string>);export default defineConfig({build: {lib: {entry: entryPoints,formats: ['es'],},rollupOptions: {external: ['react', 'react-dom'],output: {entryFileNames: '[name]/index.js',preserveModules: true,preserveModulesRoot: 'src',},},},plugins: [dts({entryRoot: 'src',outputDir: 'dist',})],
});
四、额外建议
类型声明
配合 vite-plugin-dts
插件或使用 tsc --emitDeclarationOnly
输出 .d.ts
类型文件。
混合模式
你也可以支持单入口 + 多入口共存:
// 用户既可以用:
import { Button } from 'my-ui-lib';// 也可以用:
import Button from 'my-ui-lib/button';
通过构建两个打包产物:一个 index.ts 打全库,一个多入口输出每个子模块。
五、NPM 发布结构建议
my-ui-lib/
├── package.json
├── index.js # 单入口构建产物
├── button/
│ ├── index.js # 多入口
│ └── index.d.ts
├── modal/
│ └── ...
总结推荐
目标 | 推荐方式 |
---|---|
简单快速上线 MVP | 单入口打包 |
注重组件体积、性能 | 多入口或混合模式 |
提供全量和按需引入能力 | 混合单入口 + 多入口 |