@ant-design/icons-vue 打包成多格式库
·
@ant-design/icons-vue 打包成多格式库
以下是完整的配置方案,将 @ant-design/icons-vue 打包成 UMD、ESM、CJS、AMD、IIFE 格式的
开发版和生产版。
📁 项目结构
project/
├── vite.config.advanced.js # Vite 高级配置(位于根目录)
├── build.js # 自定义构建脚本(位于根目录或 scripts/ 目录)
├── src/
│ └── index.js # 主入口文件
├── dist/ # 输出目录
│ ├── dev/ # 开发版(无压缩)
│ └── prod/ # 生产版(压缩,含 .min)
├── vite.config.js # Vite 配置
└── package.json
📄 入口文件 (src/index.js)
// src/index.js - 主入口文件
// 重新导出 @ant-design/icons-vue 的所有内容
// 具名导出所有图标
export * from '@ant-design/icons-vue'
// 默认导出所有图标
import * as icons from '@ant-design/icons-vue'
export default icons
// 为 CommonJS 环境提供兼容导出
if (typeof module !== 'undefined' && module.exports) {
module.exports = icons
module.exports.default = icons
}
// 版本信息
export const version = '__VERSION__'
⚙️ Vite 配置 (vite.config.js)
import {defineConfig} from 'vite'
import {resolve} from 'path'
import {readFileSync} from 'fs'
// 读取 package.json
const packageJson = JSON.parse(readFileSync('./package.json', 'utf-8'))
export default defineConfig(({command, mode}) => {
const isDev = mode === 'development'
const isBuild = command === 'build'
const outDir = `dist/${isDev ? 'dev' : 'prod'}`
return {
build: {
outDir,
sourcemap: isDev ? true : false,
minify: isDev ? false : 'terser',
lib: {
entry: resolve(__dirname, 'src/index.js'),
name: 'AntDesignIconsVue',
fileName: (format) => {
const formatMap = {
es: 'esm',
cjs: 'cjs',
umd: 'umd',
amd: 'amd',
iife: 'iife'
}
// 生产版添加 .min 后缀
const minSuffix = isDev ? '' : '.min'
return `ant-design-icons-vue.${formatMap[format] || format}${minSuffix}.js`
},
formats: ['es', 'cjs', 'umd', 'amd', 'iife']
},
rollupOptions: {
// 外部化 Vue 和 @ant-design/icons-vue,不打包进库
external: ['vue'],
output: {
globals: {
'vue': 'Vue',
'@ant-design/icons-vue': 'AntDesignIconsVue'
},
exports: 'named',
interop: 'auto',
// AMD 配置
amd: {
id: packageJson.name || 'ant-design-icons-vue'
},
// UMD 配置
banner: `/*! ${packageJson.name} v${packageJson.version} - ${isDev ? 'Development' : 'Production'} */`,
// 开发模式不压缩
compact: !isDev,
// 生产版使用更严格的压缩
...(isDev ? {} : {
compact: true,
generatedCode: 'es2015'
})
}
},
// 清理输出目录
emptyOutDir: isBuild,
// 详细的构建信息
reportCompressedSize: true,
// 目标环境
target: 'es2015'
},
define: {
'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'),
'__VERSION__': JSON.stringify(packageJson.version)
},
// 优化依赖
optimizeDeps: {
exclude: ['vue', '@ant-design/icons-vue']
},
// 解析配置
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
// 生产版使用更严格的压缩选项
...(isDev ? {} : {
esbuild: {
drop: ['console', 'debugger']
}
})
}
})
🔧 增强构建脚本 (build.js)
// build.js - 增强构建脚本,处理 .min 文件
import {build} from 'vite'
import {readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync} from 'fs'
import {resolve} from 'path'
const pkg = JSON.parse(readFileSync('./package.json', 'utf-8'))
async function buildAll() {
console.log('🚀 开始构建多格式图标库...\n')
// 构建开发版
console.log('📦 构建开发版(无压缩)...')
await build({
mode: 'development',
configFile: 'vite.config.js'
})
// 构建生产版
console.log('🏗️ 构建生产版(压缩,含 .min)...')
await build({
mode: 'production',
configFile: 'vite.config.js'
})
// 为生产版创建非 .min 版本(指向 .min 的软链接)
createNonMinVersions()
// 生成辅助文件
generateHelperFiles()
// 验证构建结果
validateBuild()
console.log('\n✅ 所有构建完成!')
console.log('📁 开发版: dist/dev/ (无压缩)')
console.log('📁 生产版: dist/prod/ (压缩,含 .min)')
}
function createNonMinVersions() {
console.log('🔗 创建非 .min 版本链接...')
const formats = ['esm', 'cjs', 'umd', 'amd', 'iife']
const prodDir = 'dist/prod'
formats.forEach(format => {
const minFile = `${prodDir}/ant-design-icons-vue.${format}.min.js`
const nonMinFile = `${prodDir}/ant-design-icons-vue.${format}.js`
try {
// 创建非压缩版本的副本(实际内容相同,只是文件名不同)
if (existsSync(minFile)) {
copyFileSync(minFile, nonMinFile)
console.log(` ✅ ${format}: 创建非 .min 版本`)
}
} catch (error) {
console.log(` ❌ ${format}: 创建非 .min 版本失败`, error.message)
}
})
}
function generateHelperFiles() {
// 生成 package.json 文件用于子目录引用
const subPackageJson = {
name: `${pkg.name}-dist`,
version: pkg.version,
description: pkg.description,
main: '../index.js'
}
writeFileSync('dist/package.json', JSON.stringify(subPackageJson, null, 2))
// 生成简单的类型声明文件
const typeContent = `declare module '${pkg.name}' {
export * from '@ant-design/icons-vue'
import * as icons from '@ant-design-icons-vue'
export default icons
export const version: string
}
declare module '${pkg.name}/dev' {
export * from '@ant-design/icons-vue'
}
declare module '${pkg.name}/prod' {
export * from '@ant-design/icons-vue'
}`
// 确保目录存在
const typesDir = 'dist/types'
if (!existsSync(typesDir)) {
mkdirSync(typesDir, {recursive: true})
}
writeFileSync('dist/types/index.d.ts', typeContent)
writeFileSync('dist/dev/types.d.ts', typeContent)
writeFileSync('dist/prod/types.d.ts', typeContent)
// 生成版本信息文件
writeFileSync('dist/version.json', JSON.stringify({
version: pkg.version,
buildTime: new Date().toISOString(),
formats: ['esm', 'cjs', 'umd', 'amd', 'iife']
}, null, 2))
}
function validateBuild() {
console.log('🔍 验证构建结果...')
const formats = ['esm', 'cjs', 'umd', 'amd', 'iife']
const environments = {
dev: '开发版',
prod: '生产版'
}
let allValid = true
for (const [env, desc] of Object.entries(environments)) {
console.log(`\n📂 检查 ${desc} (${env}):`)
for (const format of formats) {
const minSuffix = env === 'prod' ? '.min' : ''
const filePath = `dist/${env}/ant-design-icons-vue.${format}${minSuffix}.js`
try {
const content = readFileSync(filePath, 'utf-8')
const size = (Buffer.byteLength(content, 'utf-8') / 1024).toFixed(2)
// 基本验证
const isValid = content.includes('@ant-design/icons-vue') &&
!content.includes('vue') && // 确保不包含 Vue
content.length > 100 // 确保文件不为空
// 检查压缩情况
const isMinified = env === 'prod' &&
(content.includes('function(') ||
content.split('\n').length < 10)
if (isValid) {
console.log(` ✅ ${format.toUpperCase()}: ${size} KB${isMinified ? ' (压缩)' : ''}`)
} else {
console.log(` ❌ ${format.toUpperCase()}: 文件可能有问题`)
allValid = false
}
} catch (error) {
console.log(` ❌ ${format.toUpperCase()}: 文件不存在`)
allValid = false
}
}
}
return allValid
}
buildAll().catch(error => {
console.error('❌ 构建失败:', error)
process.exit(1)
})
📦 Package.json 配置
{
"name": "ant-design-icons-vue-bundle",
"version": "1.0.0",
"type": "module",
"description": "Bundled version of @ant-design/icons-vue in multiple formats with minified production builds",
"main": "./dist/prod/ant-design-icons-vue.cjs.js",
"module": "./dist/prod/ant-design-icons-vue.esm.js",
"browser": "./dist/prod/ant-design-icons-vue.umd.min.js",
"unpkg": "./dist/prod/ant-design-icons-vue.umd.min.js",
"jsdelivr": "./dist/prod/ant-design-icons-vue.umd.min.js",
"types": "./dist/types/index.d.ts",
"scripts": {
"dev": "vite build --mode development",
"build": "vite build --mode production",
"build:dev": "vite build --mode development --config vite.config.advanced.js",
"build:prod": "vite build --mode production --config vite.config.advanced.js",
"build:all": "npm run build:dev && npm run build:prod",
"build:advanced": "node build.js",
"prepack": "npm run build:all",
"test": "node test.js",
"serve:dev": "vite preview --outDir dist/dev",
"serve:prod": "vite preview --outDir dist/prod"
},
"files": [
"dist",
"README.md"
],
"exports": {
".": {
"types": "./dist/types/index.d.ts",
"import": {
"production": "./dist/prod/ant-design-icons-vue.esm.min.js",
"development": "./dist/dev/ant-design-icons-vue.esm.js",
"default": "./dist/prod/ant-design-icons-vue.esm.min.js"
},
"require": {
"production": "./dist/prod/ant-design-icons-vue.cjs.min.js",
"development": "./dist/dev/ant-design-icons-vue.cjs.js",
"default": "./dist/prod/ant-design-icons-vue.cjs.min.js"
},
"browser": {
"production": "./dist/prod/ant-design-icons-vue.umd.min.js",
"development": "./dist/dev/ant-design-icons-vue.umd.js",
"default": "./dist/prod/ant-design-icons-vue.umd.min.js"
}
},
"./dev": {
"types": "./dist/dev/types.d.ts",
"import": "./dist/dev/ant-design-icons-vue.esm.js",
"require": "./dist/dev/ant-design-icons-vue.cjs.js",
"browser": "./dist/dev/ant-design-icons-vue.umd.js"
},
"./prod": {
"types": "./dist/prod/types.d.ts",
"import": "./dist/prod/ant-design-icons-vue.esm.min.js",
"require": "./dist/prod/ant-design-icons-vue.cjs.min.js",
"browser": "./dist/prod/ant-design-icons-vue.umd.min.js"
},
"./package.json": "./package.json"
},
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"vue": "^3.5.21"
},
"peerDependencies": {
"@ant-design/icons-vue": "^7.0.1",
"vue": "^3.5.21"
},
"devDependencies": {
"@ant-design/icons-vue": "^7.0.1",
"vue": "^3.5.21",
"@vitejs/plugin-vue": "^4.4.0",
"vite": "^4.4.0",
"vue-tsc": "^1.8.0",
"@babel/preset-env": "^7.22.9",
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-commonjs": "^25.0.4",
"@rollup/plugin-node-resolve": "^15.1.0",
"@rollup/plugin-terser": "^0.4.3",
"@rollup/plugin-typescript": "^11.1.3",
"rollup": "^3.28.0",
"typescript": "^5.1.6"
},
"keywords": [
"icons",
"ant-design",
"vue",
"components",
"umd",
"esm",
"cjs",
"amd",
"iife",
"minified"
],
"author": "MuZone",
"license": "MIT"
}
🧪 测试文件 (test.js)
// test.js - 验证不同格式的可用性
const {readFileSync, existsSync} = require('fs')
const path = require('path')
console.log('🧪 测试构建结果...\n')
// 测试文件是否存在且基本结构正确
function testFileExistence() {
const formats = ['esm', 'cjs', 'umd', 'amd', 'iife']
const envs = [
{name: '开发版', dir: 'dev', minified: false},
{name: '生产版', dir: 'prod', minified: true}
]
console.log('📁 文件存在性测试:')
for (const env of envs) {
console.log(`\n环境: ${env.name} (${env.dir})`)
for (const format of formats) {
const minSuffix = env.minified ? '.min' : ''
const fileName = `ant-design-icons-vue.${format}${minSuffix}.js`
const filePath = path.join('dist', env.dir, fileName)
try {
const stats = require('fs').statSync(filePath)
const sizeKB = (stats.size / 1024).toFixed(2)
const icon = existsSync(filePath) ? '✅' : '❌'
console.log(` ${icon} ${format.toUpperCase()}: ${sizeKB} KB${env.minified ? ' (压缩)' : ''}`)
// 额外检查生产版的非 .min 版本
if (env.minified) {
const nonMinPath = path.join('dist', env.dir, `ant-design-icons-vue.${format}.js`)
if (existsSync(nonMinPath)) {
const nonMinStats = require('fs').statSync(nonMinPath)
console.log(` ↳ 非压缩版本: ${(nonMinStats.size / 1024).toFixed(2)} KB`)
}
}
} catch (error) {
console.log(` ❌ ${format.toUpperCase()}: 文件不存在`)
}
}
}
}
// 测试内容是否正确外部化 Vue
function testExternalization() {
console.log('\n🔍 外部化依赖测试:')
const testFiles = [
'dist/dev/ant-design-icons-vue.esm.js',
'dist/prod/ant-design-icons-vue.esm.min.js',
'dist/prod/ant-design-icons-vue.umd.min.js'
]
for (const file of testFiles) {
try {
const content = readFileSync(file, 'utf-8')
const hasVue = content.includes('require("vue")') || content.includes('from "vue"')
const hasIcons = content.includes('@ant-design/icons-vue')
if (!hasVue && hasIcons) {
console.log(` ✅ ${file}: Vue 已正确外部化`)
} else {
console.log(` ❌ ${file}: Vue 外部化可能有问题`)
}
} catch (error) {
console.log(` ❌ ${file}: 读取失败`)
}
}
}
// 测试压缩效果
function testMinification() {
console.log('\n📦 压缩效果测试:')
const pairs = [
['dist/dev/ant-design-icons-vue.esm.js', 'dist/prod/ant-design-icons-vue.esm.min.js'],
['dist/dev/ant-design-icons-vue.umd.js', 'dist/prod/ant-design-icons-vue.umd.min.js']
]
for (const [devFile, prodFile] of pairs) {
if (existsSync(devFile) && existsSync(prodFile)) {
const devSize = require('fs').statSync(devFile).size
const prodSize = require('fs').statSync(prodFile).size
const ratio = ((devSize - prodSize) / devSize * 100).toFixed(1)
console.log(` 📊 ${path.basename(devFile)} → ${path.basename(prodFile)}`)
console.log(` ${(devSize / 1024).toFixed(2)} KB → ${(prodSize / 1024).toFixed(2)} KB (减少 ${ratio}%)`)
}
}
}
// 运行测试
testFileExistence()
testExternalization()
testMinification()
console.log('\n🎉 测试完成!')
📊 输出格式详情
| 格式 | 环境 | 文件路径 | 全局变量 | 文件大小(约) | 特点 |
|---|---|---|---|---|---|
| ESM | 开发版 | dist/dev/esm.js |
- | 10-15KB | 无压缩,支持 Tree Shaking |
| ESM | 生产版 | dist/prod/esm.min.js |
- | 3-5KB | 压缩优化 |
| CJS | 开发版 | dist/dev/cjs.js |
- | 10-15KB | 无压缩,CommonJS |
| CJS | 生产版 | dist/prod/cjs.min.js |
- | 3-5KB | 压缩优化 |
| UMD | 开发版 | dist/dev/umd.js |
AntDesignIconsVue |
15-20KB | 无压缩,浏览器全局变量 |
| UMD | 生产版 | dist/prod/umd.min.js |
AntDesignIconsVue |
5-8KB | 压缩优化 |
| AMD | 开发版 | dist/dev/amd.js |
- | 15-20KB | 无压缩,RequireJS |
| AMD | 生产版 | dist/prod/amd.min.js |
- | 5-8KB | 压缩优化 |
| IIFE | 开发版 | dist/dev/iife.js |
AntDesignIconsVue |
15-20KB | 无压缩,立即执行 |
| IIFE | 生产版 | dist/prod/iife.min.js |
AntDesignIconsVue |
5-8KB | 压缩优化 |
🚀 高级压缩配置
如果需要更精细的压缩控制,可以使用以下配置:
// vite.config.advanced.js
// vite.config.advanced.js
import {defineConfig} from 'vite'
import {resolve} from 'path'
export default defineConfig(({mode}) => {
const isDev = mode === 'development'
return {
build: {
outDir: `dist/${isDev ? 'dev' : 'prod'}`,
sourcemap: isDev ? true : 'hidden',
minify: isDev ? false : 'terser',
lib: {
entry: resolve(__dirname, 'src/index.js'),
name: 'AntDesignIconsVue',
fileName: (format) => {
const formatMap = {
es: 'esm', cjs: 'cjs', umd: 'umd', amd: 'amd', iife: 'iife'
}
const minSuffix = isDev ? '' : '.min'
return `ant-design-icons-vue.${formatMap[format] || format}${minSuffix}.js`
},
formats: ['es', 'cjs', 'umd', 'amd', 'iife']
},
rollupOptions: {
external: ['vue'], //, '@ant-design/icons-vue'
output: {
globals: {
'vue': 'Vue',
'@ant-design/icons-vue': 'AntDesignIconsVue'
},
// 生产版使用高级压缩
...(isDev ? {} : {
compact: true,
generatedCode: {
arrowFunctions: true,
constBindings: true
},
// Terser 压缩选项
minifyInternalExports: true,
sanitizeFileName: true
})
}
},
// 生产版构建优化
...(isDev ? {} : {
chunkSizeWarningLimit: 1000,
assetsInlineLimit: 4096
})
},
define: {
'process.env.NODE_ENV': JSON.stringify(isDev ? 'development' : 'production'),
'__VERSION__': JSON.stringify(process.env.npm_package_version || '1.0.0')
},
// 生产版特定的优化
...(isDev ? {} : {
esbuild: {
legalComments: 'none',
minifyIdentifiers: true,
minifySyntax: true,
minifyWhitespace: true
}
})
}
})
💡 使用示例
ESM (现代浏览器/打包工具)
// 开发版 - 无压缩
import { SearchOutlined } from 'ant-design-icons-vue-bundle/dev'
// 生产版 - 压缩
import { SearchOutlined } from 'ant-design-icons-vue-bundle/prod'
// 或自动根据环境选择
import { SearchOutlined } from 'ant-design-icons-vue-bundle'
CJS (Node.js)
// 开发版
const { SearchOutlined } = require('ant-design-icons-vue-bundle/dev')
// 生产版
const { SearchOutlined } = require('ant-design-icons-vue-bundle/prod')
UMD (浏览器全局变量)
<!-- 开发版 - 无压缩 -->
<script src="path/to/ant-design-icons-vue.umd.js"></script>
<!-- 生产版 - 压缩 -->
<script src="path/to/ant-design-icons-vue.umd.min.js"></script>
<script>
// 使用方式相同
const { SearchOutlined } = AntDesignIconsVue
</script>
CDN 使用
<!-- 使用 jsDelivr CDN -->
<script src="https://cdn.jsdelivr.net/npm/ant-design-icons-vue-bundle/dist/prod/ant-design-icons-vue.umd.min.js"></script>
<!-- 使用 unpkg CDN -->
<script src="https://unpkg.com/ant-design-icons-vue-bundle/dist/prod/ant-design-icons-vue.umd.min.js"></script>
AMD (RequireJS)
// 开发版
require.config({
paths: {
'icons': 'path/to/ant-design-icons-vue.amd'
}
})
// 生产版
require.config({
paths: {
'icons': 'path/to/ant-design-icons-vue.amd.min'
}
})
require(['icons'], function(icons) {
const { SearchOutlined } = icons
})
🎯 构建和发布
- 创建项目:
mkdir antd-icons-vue
cd antd-icons-vue
npm init -y
- 安装依赖:
npm install
- 构建高级的所有格式:
npm run build:advanced
- 构建所有格式:
npm run build:all
- 仅构建开发版:
npm run build:dev
- 仅构建生产版:
npm run build:prod
- 测试构建结果:
npm test
- 预览开发版:
npm run serve:dev
- 预览生产版:
npm run serve:prod
总结这个配置方案:
- 使用 src/index.js 作为入口 - 符合项目结构最佳实践
- 生产版含 .min 后缀 - 清晰区分压缩版和非压缩版
- 不包含 Vue 依赖 - 通过 external 配置正确外部化
- 多格式支持 - 完整的 5 种模块格式
- 开发/生产分离 - 分别构建优化版和调试版
- 完整的压缩优化 - 生产版文件大小显著减少
- CDN 友好 - 为 CDN 使用优化了配置
更多推荐




所有评论(0)