Skip to content

在 Vite 项目中实现自动生成 package.json 的打包优化方案

背景需求

当我们将项目发布到 npm 时,通常需要去除打包目录的多余层级结构。以如下项目结构为例:

my-project
├─ README.md
├─ package.json
├─ packages
│  ├─ cjs
│  └─ es

我们需要让最终发布的包结构直接包含构建产物,而非通过 packages 目录访问。解决方案是在构建时自动生成适用于发布的 package.json 到目标目录(如 dist)。

实现方案

方案一:使用官方推荐插件

推荐工具rollup-plugin-generate-package-json
GitHub 仓库

实现步骤

  1. 安装依赖
bash
npm install rollup-plugin-generate-package-json -D
  1. 配置 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)

方案对比

特性官方插件方案自定义插件方案
上手难度★☆☆☆☆★★★☆☆
可定制性★★☆☆☆★★★★★
依赖管理自动手动
类型支持完善需自行实现
适合场景标准需求特殊定制需求
长期维护成本中高

实施建议

  1. 优先使用官方插件:满足大部分常规场景需求
  2. 渐进式定制:先在官方插件基础上通过 baseContents 扩展,必要时再自定义
  3. 关键字段验证:确保包含以下必要字段:
    json
    {
      "name": "your-package",
      "version": "1.0.0",
      "main": "cjs/index.js",
      "module": "es/index.js",
      "types": "es/index.d.ts",
      "files": ["**/*"]
    }
  4. 版本同步:建议配合 npm version 命令实现自动版本管理

注意事项

  1. 路径配置需使用绝对路径
  2. 生产环境应移除开发依赖(devDependencies)
  3. 使用 exports 字段时注意 Node.js 版本兼容性
  4. 建议添加构建后验证脚本:
bash
#!/bin/bash
cd dist && npm pack --dry-run

通过合理选择实施方案,可以有效提升 npm 包的发布效率和质量控制。两种方案各有优势,建议根据项目实际需求进行选择。