在 Vite 项目中实现自动生成 package.json 的打包优化方案
背景需求
当我们将项目发布到 npm 时,通常需要去除打包目录的多余层级结构。以如下项目结构为例:
my-project
├─ README.md
├─ package.json
├─ packages
│ ├─ cjs
│ └─ es
我们需要让最终发布的包结构直接包含构建产物,而非通过 packages
目录访问。解决方案是在构建时自动生成适用于发布的 package.json
到目标目录(如 dist
)。
实现方案
方案一:使用官方推荐插件
推荐工具:rollup-plugin-generate-package-json
(GitHub 仓库)
实现步骤
- 安装依赖
bash
npm install rollup-plugin-generate-package-json -D
- 配置
vite.config.js
javascript
import generatePackageJson from "rollup-plugin-generate-package-json";
export default defineConfig({
build: {
rollupOptions: {
plugins: [
generatePackageJson({
outputFolder: "dist",
baseContents: (pkg) => ({
name: pkg.name,
version: pkg.version,
main: "cjs/index.js",
module: "es/index.js",
types: "es/index.d.ts",
exports: {
".": {
import: "./es/index.js",
require: "./cjs/index.js",
},
},
}),
additionalDependencies: {
// 声明运行时依赖
"lodash-es": "^4.17.21",
},
}),
],
},
},
});
方案优势
- 官方维护,稳定性强
- 支持依赖自动合并
- 提供类型提示
- 支持增量更新
方案二:自定义 Rollup 插件
适用场景:需要高度定制化或特殊字段处理
完整实现
javascript
// plugins/rollup-plugin-generate-package-json.js
import fs from "fs";
import path from "path";
export default function generatePackageJsonPlugin(options = {}) {
const { input, output } = options;
return {
name: "generate-package-json",
generateBundle(OutputOptions) {
const inputDir = input ? path.resolve(process.cwd(), input, "package.json") : path.resolve(process.cwd(), "package.json");
const outDir = output || OutputOptions.dir || path.dirname(OutputOptions.file);
// 读取项目根目录的 package.json
const pkg = JSON.parse(fs.readFileSync(inputDir, "utf-8"));
// 定义要生成的 package.json 内容
const distPackage = {
name: pkg.name,
version: pkg.version,
...
};
// 写入到构建目录
const outputPath = path.join(outDir, "package.json");
fs.writeFileSync(outputPath, JSON.stringify(distPackage, null, 2));
},
};
}
// vite.config.js
import generatePackageJson from "./plugins/rollup-plugin-generate-package-json";
export default defineConfig({
build: {
rollupOptions: {
plugins: [
generatePackageJson({
output: "packages",
}),
]
}
}
})
功能特性
- 支持字段过滤白名单
- 可添加自定义字段
- 自动路径解析
- 类型安全校验(推荐配合 TypeScript)
方案对比
特性 | 官方插件方案 | 自定义插件方案 |
---|---|---|
上手难度 | ★☆☆☆☆ | ★★★☆☆ |
可定制性 | ★★☆☆☆ | ★★★★★ |
依赖管理 | 自动 | 手动 |
类型支持 | 完善 | 需自行实现 |
适合场景 | 标准需求 | 特殊定制需求 |
长期维护成本 | 低 | 中高 |
实施建议
- 优先使用官方插件:满足大部分常规场景需求
- 渐进式定制:先在官方插件基础上通过
baseContents
扩展,必要时再自定义 - 关键字段验证:确保包含以下必要字段:json
{ "name": "your-package", "version": "1.0.0", "main": "cjs/index.js", "module": "es/index.js", "types": "es/index.d.ts", "files": ["**/*"] }
- 版本同步:建议配合
npm version
命令实现自动版本管理
注意事项
- 路径配置需使用绝对路径
- 生产环境应移除开发依赖(devDependencies)
- 使用
exports
字段时注意 Node.js 版本兼容性 - 建议添加构建后验证脚本:
bash
#!/bin/bash
cd dist && npm pack --dry-run
通过合理选择实施方案,可以有效提升 npm 包的发布效率和质量控制。两种方案各有优势,建议根据项目实际需求进行选择。