别再写改名脚本了,一个 Vite 插件搞定压缩、校验、自动哈希命名vite-plugin-pack-orchestrator

📦 Vite 构建压缩插件:vite-plugin-pack-orchestrator

🤔 为什么又造一个轮子?

市面上已经有一些 Vite 打包插件,比如 vite-plugin-zip-packvite-plugin-compress 等,能用,但总差那么点意思 --- 大多只支持 ZIP,功能也比较单一。

实际项目里,打包这个环节往往没那么简单:

  1. 多种压缩格式 🗜️ --- ZIP 方便分享给同事,TAR.GZ 部署到 Linux 服务器,7Z 追求更高压缩比存档归档,不同场景需要不同格式
  2. 文件校验 🔐 --- 打包后需要 MD5/SHA1 校验值来确认版本一致性,尤其是发布给客户的场景
  3. 灵活命名 ✏️ --- 版本号、时间戳、哈希值,文件名里能带的信息越多越好
  4. CI/CD 友好 🚀 --- 流水线里每次构建产物都应该是唯一可追溯的,压缩后自动带哈希改名,省去人工处理的麻烦(写脚本去改也麻烦一些)

现有插件基本没法同时满足这些,所以写了 vite-plugin-pack-orchestrator

⚡ 和其他插件有什么不同

功能 大多数打包插件 本插件
压缩格式 仅 ZIP ZIP / TAR / TAR.GZ / 7Z
校验和 MD5 / SHA1 / SHA256
文件名模板 固定命名 支持 [name] [version] [timestamp] [hash] 占位符
Hook 扩展 onBeforeBuild / onAfterBuild / onError 等钩子
文件过滤 部分支持 include + exclude glob 模式
7Z 支持 需要系统安装 7z 内置,零依赖
输出目录控制 固定位置 archiveOutDir 自定义

📥 安装

bash 复制代码
npm install vite-plugin-pack-orchestrator

🚀 快速上手

最基本的用法,两行配置搞定:

typescript 复制代码
// vite.config.ts
import { defineConfig } from 'vite';
import orchestrator from 'vite-plugin-pack-orchestrator';

export default defineConfig({
  plugins: [
    orchestrator({
      pack: {
        outDir: 'dist',          // 要打包的目录,默认就是 'dist'
        format: 'zip',           // 压缩格式:zip | tar | tar.gz | 7z
        fileName: 'myapp',       // 压缩包文件名
      },
    }),
  ],
  build: { outDir: 'dist' },
});

执行 vite build 后,会在项目根目录生成 myapp.zip

⚙️ 配置项详解

pack --- 打包配置

typescript 复制代码
pack: {
  outDir: 'dist',              // 要打包的源目录(相对于项目根目录),默认 'dist'
  fileName: 'myapp',           // 文件名,支持占位符(见下方说明)
  format: 'zip',               // 压缩格式:'zip' | 'tar' | 'tar.gz' | '7z'
  compressionLevel: 9,         // 压缩级别 0-9,默认 9(最高压缩率)
  archiveOutDir: './releases', // 压缩包输出目录,不写默认项目根目录
  exclude: ['**/*.map'],       // 排除的文件(glob 匹配)
  include: ['**/*.js'],        // 只包含的文件(可选,不设置则包含全部)
}

fileName 占位符

文件名支持以下占位符,打包时自动替换:

占位符 说明 示例值
[name] package.json 中的 name my-awesome-app
[version] package.json 中的 version 1.2.0
[timestamp] 当前时间戳 1714012345678
[hash] 构建内容 MD5 哈希(完整 32 位) a1b2c3d4e5f6...
[hash:8] MD5 哈希前 N 位(自定义长度) a1b2c3d4
typescript 复制代码
// 示例:fileName 设为 'release-[version]-[timestamp]'
// 输出:release-1.2.0-1714012345678.zip

// 示例:fileName 设为 '[name]-v[version]'
// 输出:my-awesome-app-v1.2.0.zip

// 示例:fileName 设为 '[name]-[hash]'
// 输出:my-awesome-app-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.zip

// 示例:fileName 设为 '[name]-[hash:8]'
// 输出:my-awesome-app-a1b2c3d4.zip

如果 fileName 不包含扩展名,插件会根据 format 自动追加 .zip.tar.gz 等后缀。

🔗 hooks --- 钩子函数

onBeforeBuild --- 构建前执行

在 Vite 开始打包之前执行,适合做一些前置清理工作:

typescript 复制代码
hooks: {
  onBeforeBuild: async () => {
    // 构建前的一些处理
  },
}
onBundleGenerated --- bundle 生成后执行

Vite bundle 生成后、压缩包创建前执行,可以拿到构建产物信息:

typescript 复制代码
hooks: {
  onBundleGenerated: (bundle) => {
    console.log('生成的文件:', Object.keys(bundle));
  },
}
onAfterBuild --- 压缩完成后执行(核心)

这是本插件最强大的功能。 压缩包创建完成后,插件会自动计算 MD5 / SHA1 / SHA256 三种校验和,然后传给 onAfterBuild。你可以利用这些校验和来重命名压缩包

返回一个新路径(和原路径不同),插件会自动重命名文件:

typescript 复制代码
hooks: {
  onAfterBuild: (path, format, checksums) => {
    // path      --- 当前压缩包的完整路径
    // format    --- 压缩格式('zip' | 'tar' | 'tar.gz' | '7z')
    // checksums --- 校验和对象:{ md5: string, sha1: string, sha256: string }
    return path; // 返回原路径则不重命名
  },
}

实际案例:

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

// 案例 2:用 MD5 全量替换文件名
// myapp.zip → a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.zip
onAfterBuild: (path, format, checksums) =>
  path.replace(/^.+(?=\.\w+$)/, checksums.md5);

// 案例 3:追加格式和哈希到原始文件名
// myapp.zip → myapp-zip-a1b2c3d4.zip
onAfterBuild: (path, format, checksums) =>
  path.replace(/(\.\w+)$/, `-${format}-${checksums.sha256.slice(0, 8)}$1`);

// 案例 4:完全自定义文件名,用 format 参数自动适配后缀
// myapp.zip → release-a1b2c3d4e5f6.zip
onAfterBuild: (path, format, checksums) =>
  `release-${checksums.md5.slice(0, 12)}.${format}`;

// 案例 5:不重命名,只是拿校验和做点其他事(比如写入文件)
onAfterBuild: async (path, format, checksums) => {
  fs.writeFileSync('checksums.json', JSON.stringify(checksums));
  // 不 return 或 return 原路径 = 不重命名
}
onError --- 出错时执行

打包失败时回调,适合接入告警通知:

typescript 复制代码
hooks: {
  onError: async (error) => {
    console.error('打包出错了:', error.message);
    // 可以在这里接入钉钉/企业微信告警
  },
}

🔄 为什么说压缩后自动改名对 CI/CD 很重要?

在持续集成/持续部署的流水线中,每次构建的产物都需要是唯一可追溯 的。如果压缩包文件名固定叫 dist.zip,你怎么知道这次构建和上次有什么区别?回滚的时候该拿哪个版本?

本插件通过 onAfterBuild 钩子拿到校验和后,可以自动在文件名中插入哈希值:

typescript 复制代码
hooks: {
  onAfterBuild: (path, format, checksums) =>
    path.replace(/(\.zip)$/, `-${checksums.sha1.slice(0, 8)}$1`);
}

构建后输出:

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

文件名本身就是指纹 🔑,一眼就能区分不同构建,部署脚本直接按文件名定位版本,不需要额外维护版本映射表。回滚也简单 --- 找到上一个哈希文件名部署即可。配合 [version] [timestamp] 占位符,追溯性更强。

🎯 完整示例

把前面的配置合在一起,就是一个完整的生产级配置:

typescript 复制代码
// vite.config.ts
import { defineConfig } from 'vite';
import orchestrator from 'vite-plugin-pack-orchestrator';

export default defineConfig({
  plugins: [
    orchestrator({
      pack: {
        outDir: 'dist',                    // 打包 dist 目录
        fileName: 'myapp-[version]',       // 文件名带版本号
        format: 'zip',                     // ZIP 格式
        archiveOutDir: './releases',       // 输出到 releases 目录
        exclude: ['**/*.map'],             // 排除 sourcemap
      },
      hooks: {
        // 压缩完成后自动加上 SHA1 哈希
        onAfterBuild: (path, format, checksums) =>
          path.replace(/(\.(?:zip|tar\.gz|tar|7z))$/, `-${checksums.sha1.slice(0, 8)}$1`),
        // 出错时打印日志
        onError: (error) => console.error('打包失败:', error.message),
      },
    }),
  ],
  build: { outDir: 'dist' },
});

vite build 一次搞定,不需要额外的打包脚本。


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

相关推荐
a11177610 小时前
可视化角色权限配置页面(html 开源)
前端·开源·html
Lee川10 小时前
个人中心与 AI 头像生成:从页面到 DALL-E 的完整实现
前端·架构
tedcloud12316 小时前
UI-TARS-desktop部署教程:构建AI桌面自动化系统
服务器·前端·人工智能·ui·自动化·github
UXbot19 小时前
AI原型设计工具如何支持团队协作与快速迭代
前端·交互·个人开发·ai编程·原型模式
ZC跨境爬虫19 小时前
跟着MDN学HTML_day_48:(Node接口)
前端·javascript·ui·html·音视频
PieroPc21 小时前
CAMWATCH — 局域网摄像头监控系统 Fastapi + html
前端·python·html·fastapi·监控
巴巴博一1 天前
2026 最新:Trae / Cursor 一键接入 taste-skill 完整教程(让 AI 前端告别“AI 味”)
前端·ai·ai编程
kyriewen1 天前
半夜三点线上崩了,AI替我背了锅——用AI排错,五分钟定位三年老bug
前端·javascript·ai编程
kyriewen1 天前
我让 AI 当了 24 小时全年无休的“毒舌考官”
前端·ci/cd·ai编程
hexu_blog1 天前
vue+java实现图片批量压缩
java·前端·vue.js