@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
})

🎯 构建和发布

  1. 创建项目:
mkdir antd-icons-vue
cd antd-icons-vue
npm init -y
  1. 安装依赖:
npm install
  1. 构建高级的所有格式:
npm run build:advanced
  1. 构建所有格式:
npm run build:all
  1. 仅构建开发版:
npm run build:dev
  1. 仅构建生产版:
npm run build:prod
  1. 测试构建结果:
npm test
  1. 预览开发版:
npm run serve:dev
  1. 预览生产版:
npm run serve:prod

总结这个配置方案:

  1. 使用 src/index.js 作为入口 - 符合项目结构最佳实践
  2. 生产版含 .min 后缀 - 清晰区分压缩版和非压缩版
  3. 不包含 Vue 依赖 - 通过 external 配置正确外部化
  4. 多格式支持 - 完整的 5 种模块格式
  5. 开发/生产分离 - 分别构建优化版和调试版
  6. 完整的压缩优化 - 生产版文件大小显著减少
  7. CDN 友好 - 为 CDN 使用优化了配置
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐