构建完自动打包压缩,一个插件搞定 Vite / Webpack / Rollup / ESBuild

之前写了一个 Vite 专用的打包归档插件 vite-plugin-pack-orchestrator文章地址。能用,但只支持 Vite --- 老项目用 Webpack,库开发用 Rollup,ESBuild(小型库) 也越来越主流,总不能每个构建器各写一套打包逻辑。

所以用 unplugin 重写了一版:unplugin-pack-orchestrator,一套 API,四个构建器通用。


🤔 unplugin是啥好玩意?

一句话:Unplugin 是一套通用插件开发框架,写一套插件代码,就能同时适配 Vite、Webpack、Rollup、esbuild、Rspack 等几乎所有前端打包工具,不用为每个工具单独写一套插件。 作者就是大家熟悉的Anthony Fu小哥

核心解决什么痛点?

前端打包工具太多:Vite、Webpack、Rollup、esbuild......它们的插件 API 完全不一样

  • Webpack 用自己的 compiler 钩子
  • Vite 复用 Rollup 钩子,但细节不同
  • esbuild 又是另一套

以前写插件,要分别维护多套代码,非常麻烦。

Unplugin 做了一层适配层:你只写一套基于 Rollup 风格的统一钩子,它自动帮你翻译成各个打包工具能识别的格式。


📑 你肯定用过的 Unplugin 插件(高频)

这些都是用 Unplugin 做的,Vite/Webpack 通用:

  1. unplugin-auto-import:自动导入 Vue、React、工具函数,不用手动 import
  2. unplugin-vue-components:Vue 组件自动按需导入
  3. unplugin-icons:图标组件按需引入
  4. unplugin-turbo-console:美化 console 日志
  5. ...

所以写了这个插件,把这些问题一块解决了。


⚡ 和其他插件有什么不同

功能 多数打包插件 unplugin-pack-orchestrator
构建器支持 仅 Vite Vite / Webpack / Rollup / ESBuild
压缩格式 仅 ZIP ZIP / TAR / TAR.GZ / 7Z
校验和 MD5 / SHA1 / SHA256
文件名模板 固定命名 [name][version][timestamp][hash] 占位符
Hook 扩展 onBeforeBuild / onAfterBuild / onError 等
文件过滤 部分支持 include + exclude glob 模式
7Z 支持 需要系统安装 7z 内置
自动重命名 onAfterBuild 返回新路径即自动重命名

📦 安装

perl 复制代码
npm install unplugin-pack-orchestrator -D

🚀 快速上手

四个构建器,同一套 API,只是导入路径不同:

Vite:

ts 复制代码
    // vite.config.ts
    import packOrchestrator from 'unplugin-pack-orchestrator/vite'

    export default defineConfig({
      plugins: [
        packOrchestrator({
          pack: { format: 'zip', fileName: 'myapp-[version]', outDir: 'dist' },
        }),
      ],
    })

Webpack:

js 复制代码
    // webpack.config.js
    const packOrchestrator = require('unplugin-pack-orchestrator/webpack')

    module.exports = {
      plugins: [
        packOrchestrator({
          pack: { format: 'zip', fileName: 'app-[name]-[version]', outDir: 'dist' },
        }),
      ],
    }

Rollup:

js 复制代码
    // rollup.config.js
    import packOrchestrator from 'unplugin-pack-orchestrator/rollup'

    export default {
      plugins: [
        packOrchestrator({
          pack: { format: 'tar.gz', fileName: 'bundle-[name]', outDir: 'dist' },
        }),
      ],
    }

ESBuild:

js 复制代码
    // build.js
    const packOrchestrator = require('unplugin-pack-orchestrator/esbuild')

    require('esbuild').build({
      outdir: 'dist',
      plugins: [
        packOrchestrator({
          pack: { format: '7z', fileName: 'build-[name]-[version]', outDir: 'dist' },
        }),
      ],
    })

构建完成后,项目根目录自动生成归档文件,不用额外操作。


⚙️ 配置项

js 复制代码
    pack: {
      outDir: 'dist',               // 要打包的源目录
      fileName: '[name]-[version]', // 文件名,支持占位符
      format: 'zip',                // zip | tar | tar.gz | 7z
      compressionLevel: 9,          // 压缩级别 0-9
      archiveOutDir: './releases',  // 归档输出目录,默认项目根目录
      include: ['**/*'],            // 包含文件(glob)
      exclude: ['**/*.map'],        // 排除文件(glob)
    }

fileName 占位符

占位符 说明 示例
[name] package.json name my-app
[version] package.json version 1.2.0
[timestamp] 当前时间戳(毫秒) 1714012345678
[hash] 构建产物 MD5(32 位) a1b2c3d4e5f6a7b8...
[hash:8] MD5 前 N 位 a1b2c3d4

文件名不写扩展名,插件根据 format 自动追加。


🔗 hooks --- 生命周期钩子

钩子 参数 触发时机
onBeforeBuild () 构建开始前
onBundleGenerated (bundle) 产物生成后、归档前
onAfterBuild (archivePath, format, checksums) 归档完成后
onError (error) 出错时

onAfterBuild --- 最核心的钩子

归档创建完成后,插件自动计算 MD5 / SHA1 / SHA256 校验和,传给回调。返回一个不同的路径即可自动重命名

js 复制代码
    // 扩展名前插入 SHA1 短哈希:myapp.zip → myapp-3a7b2c1d.zip
    onAfterBuild: (path, format, checksums) =>
      path.replace(/(.(?:zip|tar.gz|tar|7z))$/, `-${checksums.sha1.slice(0, 8)}$1`)

    // 用 MD5 替换整个文件名:myapp.zip → a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.zip
    onAfterBuild: (path, format, checksums) =>
      path.replace(/^.+(?=.\w+$)/, checksums.md5)

    // 完全自定义:myapp.zip → release-a1b2c3d4e5f6.zip
    onAfterBuild: (path, format, checksums) =>
      `release-${checksums.md5.slice(0, 12)}.${format}`

    // 不重命名,只拿校验和写文件
    onAfterBuild: (path, format, checksums) => {
      fs.writeFileSync('checksums.json', JSON.stringify(checksums))
    }

checksums 结构:{ md5: string; sha1: string; sha256: string }


🔄 为什么说自动重命名对 CI/CD 很重要?

流水线里每次构建产物都得是唯一可追溯的。文件名固定叫 dist.zip,你分不清这是第几次构建,回滚也不知道拿哪个。

onAfterBuild 追加哈希后:

python 复制代码
myapp-1.0.0-3a7b2c1d.zip
myapp-1.0.1-7f9e4b2a.zip

文件名本身就是指纹 🔑 --- 部署脚本按文件名定位版本,回滚找上一个哈希文件名就行。配合 [version][timestamp]占位符,追溯性更强,不需要额外维护版本映射表。


🎯 生产级配置

ts 复制代码
    // vite.config.ts
    import { defineConfig } from 'vite'
    import packOrchestrator from 'unplugin-pack-orchestrator/vite'

    export default defineConfig({
      plugins: [
        packOrchestrator({
          pack: {
            outDir: 'dist',
            fileName: 'release-[name]-v[version]',
            format: 'zip',
            archiveOutDir: './releases',
            exclude: ['**/*.map', '**/*.d.ts', 'node_modules/**'],
          },
          hooks: {
            // 归档后自动追加 SHA1 哈希
            onAfterBuild: (path, format, checksums) =>
              path.replace(/(.(?:zip|tar.gz|tar|7z))$/, `-${checksums.sha1.slice(0, 8)}$1`),
            onError: (err) => console.error('打包失败:', err.message),
          },
        }),
      ],
    })

vite build 一次搞定,不用额外打包脚本。


插件很轻量,代码开源,欢迎试用和提建议 🎉

相关推荐
Hello--_--World1 天前
vite:什么是热更新?vite 和 webpack 有什么区别?vite常见配置和优化手段?
前端·webpack·node.js
Hello--_--World1 天前
Vite:什么是bundleless?哪些要打包,哪些不要打包?依赖预构建是什么?依赖预构建如何减少网络请求的?esbuild 又是什么?
前端·javascript·webpack·vite
Rooting++1 天前
vue2+webpack打包优化的相关问题
前端·webpack·node.js
VillenK2 天前
版本依赖问题:vite-plugin-dts@3.1.0 与 jiti 的兼容性
前端·typescript·vite
Tatan3 天前
【里程碑二】基于webpack5完成的多前端工程化建设
webpack
閞杺哋笨小孩5 天前
从脚手架到构建注入:Vue 多租户「入驻」工程实践
vue.js·vite
Hello--_--World6 天前
Webpack:Webpack 核心配置、什么是 Loader? 什么是plugin?webpack 构建流程
前端·webpack·node.js
前端若水7 天前
安装 markdown-it 后项目报错,可能是 Vue/Webpack 项目中 Quill 的问题(ES6+ 语法不支持)
vue.js·webpack·es6
李白的天不白7 天前
代码引用错误和性能优化建议。
webpack