Vue 3 与 Rollup 库开发

概述

Rollup 是一款高效的模块打包工具,特别适合构建 JavaScript 库和组件。与 Vite 不同,Rollup 专注于生成更小、更高效的代码,支持多种输出格式,是开发 Vue 3 组件库和工具库的理想选择。本集将深入探讨如何使用 Rollup 开发和构建 Vue 3 库,包括配置、打包策略、最佳实践和发布流程。

核心知识点

1. Rollup 基础配置

创建一个基础的 Rollup 配置文件 rollup.config.js

// rollup.config.js
import vue from '@vitejs/plugin-vue'
import typescript from '@rollup/plugin-typescript'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import terser from '@rollup/plugin-terser'

export default {
  input: 'src/index.ts', // 入口文件
  output: [
    // 多种输出格式
    {
      file: 'dist/library.esm.js',
      format: 'es', // ES 模块
      sourcemap: true
    },
    {
      file: 'dist/library.cjs.js',
      format: 'cjs', // CommonJS
      sourcemap: true
    },
    {
      file: 'dist/library.umd.js',
      format: 'umd', // UMD 格式
      name: 'MyLibrary', // 全局变量名
      sourcemap: true,
      globals: {
        vue: 'Vue' // 外部依赖映射
      }
    }
  ],
  plugins: [
    vue(),
    typescript(),
    resolve(),
    commonjs(),
    terser() // 代码压缩
  ],
  external: ['vue'] // 外部依赖,不打包到输出文件
}

2. 项目结构设计

library-project/
├── src/
│   ├── components/        # Vue 组件
│   │   └── MyComponent.vue
│   ├── composables/       # 组合式函数
│   │   └── useMyFeature.ts
│   ├── utils/             # 工具函数
│   │   └── helpers.ts
│   └── index.ts           # 入口文件,导出所有内容
├── rollup.config.js       # Rollup 配置
├── tsconfig.json          # TypeScript 配置
├── package.json           # 项目配置
└── README.md              # 项目说明

3. 入口文件设计

入口文件 src/index.ts 用于导出库的所有公共 API:

// src/index.ts
// 导出组件
export { default as MyComponent } from './components/MyComponent.vue'

// 导出组合式函数
export { default as useMyFeature } from './composables/useMyFeature'

export * from './composables/useMyFeature'

// 导出工具函数
export * from './utils/helpers'

4. 组件开发规范

开发 Vue 3 组件时,遵循以下规范:

<!-- src/components/MyComponent.vue -->
<template>
  <div class="my-component">
    <slot></slot>
  </div>
</template>

<script setup lang="ts">
defineProps<{
  // 定义组件属性
  color?: string
  size?: 'small' | 'medium' | 'large'
}>()

// 定义组件事件
const emit = defineEmits<{
  (e: 'click', event: MouseEvent): void
}>()
</script>

<style scoped>
.my-component {
  /* 组件样式 */
}
</style>

5. 组合式函数设计

创建可复用的组合式函数:

// src/composables/useMyFeature.ts
import { ref, computed } from 'vue'

export default function useMyFeature(initialValue = 0) {
  const count = ref(initialValue)
  const doubled = computed(() => count.value * 2)
  
  function increment() {
    count.value++
  }
  
  return {
    count,
    doubled,
    increment
  }
}

6. TypeScript 配置

配置 TypeScript 以支持 Vue 3 和 Rollup 构建:

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "declaration": true, // 生成类型声明文件
    "emitDeclarationOnly": true,
    "outDir": "dist",
    "types": ["vite/client"]
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

7. 打包命令配置

package.json 中配置打包命令:

{
  "name": "my-vue3-library",
  "version": "1.0.0",
  "type": "module",
  "main": "dist/library.cjs.js",
  "module": "dist/library.esm.js",
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/library.esm.js",
      "require": "./dist/library.cjs.js"
    }
  },
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w"
  },
  "peerDependencies": {
    "vue": "^3.3.0"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^25.0.0",
    "@rollup/plugin-node-resolve": "^15.0.0",
    "@rollup/plugin-terser": "^0.4.0",
    "@rollup/plugin-typescript": "^11.0.0",
    "@vitejs/plugin-vue": "^4.5.0",
    "rollup": "^3.20.0",
    "typescript": "^5.0.0",
    "vue": "^3.3.0"
  }
}

8. 外部依赖处理

使用 external 选项处理外部依赖:

// rollup.config.js
export default {
  // ...
  external: (id) => {
    // 外部依赖规则
    return id.startsWith('vue') || id.startsWith('@vue/')
  },
  // ...
}

9. 资源处理

使用插件处理静态资源:

// rollup.config.js
import url from '@rollup/plugin-url'
import image from '@rollup/plugin-image'

export default {
  // ...
  plugins: [
    // ...
    url({
      limit: 8192, // 小于 8KB 的资源转为 base64
      include: ['**/*.svg', '**/*.png', '**/*.jpg', '**/*.gif'],
      emitFiles: true
    }),
    image()
  ],
  // ...
}

10. 多环境构建

配置不同环境的构建选项:

// rollup.config.js
import { defineConfig } from 'rollup'

const isProduction = process.env.NODE_ENV === 'production'

export default defineConfig({
  // ...
  output: [
    // ...
    {
      // ...
      plugins: [isProduction && terser()]
    }
  ],
  plugins: [
    // ...
    isProduction && terser()
  ].filter(Boolean),
  // ...
})

最佳实践

1. 类型安全

  • 为所有导出的 API 添加完整的 TypeScript 类型定义
  • 生成 .d.ts 类型声明文件
  • 使用 tsc --noEmit 进行类型检查

2. 组件设计原则

  • 单一职责原则:每个组件只负责一个功能
  • 可配置性:通过 props 提供灵活的配置选项
  • 可扩展性:支持插槽和自定义事件
  • 无障碍支持:确保组件符合 accessibility 标准

3. 测试策略

  • 单元测试:测试组件的各个功能点
  • 集成测试:测试组件间的交互
  • E2E 测试:测试组件在真实环境中的表现
  • 快照测试:确保组件渲染结果一致

4. 文档编写

  • 使用 Storybook 或 VitePress 生成组件文档
  • 为每个 API 添加详细的 JSDoc 注释
  • 提供使用示例和最佳实践
  • 包含迁移指南和版本变更日志

5. 发布流程

  1. 确保所有测试通过
  2. 更新版本号(遵循 SemVer)
  3. 生成构建产物
  4. 提交代码并打标签
  5. 发布到 npm
  6. 更新文档

常见问题和解决方案

1. Vue 组件打包问题

问题:Vue 组件打包后无法正常使用

解决方案

  • 确保使用 @vitejs/plugin-vue 处理 Vue 文件
  • 检查 Vue 版本兼容性
  • 确保组件使用正确的导出方式

2. 类型声明问题

问题:生成的类型声明文件不完整

解决方案

  • 配置 tsconfig.json 中的 declaration: trueemitDeclarationOnly: true
  • 使用 rollup-plugin-dts 生成类型声明
  • 手动检查和补充类型定义

3. 外部依赖冲突

问题:使用库时出现依赖冲突

解决方案

  • peerDependencies 中声明外部依赖
  • 明确指定依赖版本范围
  • 提供清晰的依赖安装指南

4. 资源路径问题

问题:打包后的资源路径不正确

解决方案

  • 使用 @rollup/plugin-url@rollup/plugin-image 处理资源
  • 配置正确的 publicPath
  • 考虑使用相对路径或 CDN 资源

5. 多平台兼容性

问题:库在某些平台上无法正常工作

解决方案

  • 测试多种浏览器和 Node.js 版本
  • 使用 Babel 进行代码转译
  • 提供多种输出格式
  • 避免使用平台特定的 API

进阶学习资源

  1. 官方文档

  2. 优质插件

  3. 学习案例

  4. 工具链

实践练习

练习 1:创建基础库

  1. 初始化一个 Rollup + Vue 3 库项目
  2. 实现一个简单的 Vue 组件
  3. 配置 Rollup 打包多种格式
  4. 生成类型声明文件

练习 2:组件库开发

  1. 创建一个包含多个组件的组件库
  2. 实现组合式函数和工具函数
  3. 配置资源处理和外部依赖
  4. 编写组件文档和示例

练习 3:高级配置

  1. 配置多环境构建(开发/生产)
  2. 实现代码分割和懒加载
  3. 配置资源优化和压缩
  4. 添加构建分析和可视化

练习 4:发布流程

  1. 配置 package.json 的各种字段
  2. 实现自动化测试和构建
  3. 创建 CHANGELOG 和版本管理
  4. 发布到 npm 并验证

总结

使用 Rollup 开发 Vue 3 库是一个高效、灵活的选择。通过合理的配置和最佳实践,你可以创建出高质量、易维护、广泛兼容的 Vue 3 库。从基础配置到高级优化,从组件设计到发布流程,掌握 Rollup 库开发技能将使你能够更好地贡献 Vue 3 生态系统。

下一集我们将学习 Vue 3 与 Vitest 高级测试,敬请期待!

« 上一篇 Vue 3与Vite插件开发 - 构建工具扩展全栈解决方案 下一篇 » Vue 3与Vitest高级测试 - 现代化测试全栈解决方案