之前写了一个 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 通用:
unplugin-auto-import:自动导入 Vue、React、工具函数,不用手动 importunplugin-vue-components:Vue 组件自动按需导入unplugin-icons:图标组件按需引入unplugin-turbo-console:美化 console 日志- ...
所以写了这个插件,把这些问题一块解决了。
⚡ 和其他插件有什么不同
| 功能 | 多数打包插件 | 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 一次搞定,不用额外打包脚本。
插件很轻量,代码开源,欢迎试用和提建议 🎉
- npm : unplugin-pack-orchestrator
- Gitee : unplugin-pack-orchestrator
- GitHub : wangkai000/unplugin-pack-orchestrator
