跳过正文
  1. 文章/

Rollup 配置选项

·9978 字·20 分钟·
hujiacheng
作者
hujiacheng
Front-end Developer / Strive To Become Better
目录
版本说明

本文档基于 Rollup 4.x 编写,包含最新的配置选项和最佳实践。如果你使用旧版本 Rollup,某些选项可能不可用。

主要更新

  • ✅ 新增 treeshake.preset(‘smallest’ | ‘safest’ | ‘recommended’)预设配置
  • ✅ 新增 preserveModulesmanualChunksinterop 等高级输出选项
  • ✅ 新增 Watch 模式详细配置和编程式 API
  • ✅ 新增性能优化章节(缓存、并行处理、插件顺序)
  • ✅ 补充 @rollup/plugin-alias 等常用插件配置
  • ✅ 提供 JavaScript/TypeScript/Vue 3 组件库的完整配置模板
注意事项
  • 配置选项会随 Rollup 版本更新而变化
  • 不同的项目类型(库/应用)需要不同的配置策略
  • Vite 在生产环境使用 Rollup,可参考 vite.config.ts 中的 build.rollupOptions
  • 建议使用官方插件(@rollup/plugin-*),社区插件需注意维护状态

什么是 Rollup
#

Rollup 是一个用于 JavaScript 的模块打包器,它将点滴代码编织成错综复杂的程序。Rollup 对代码模块使用新的标准化格式(ES modules),而不是传统的 CommonJS 和 AMD。

# 安装 Rollup
npm install -D rollup

# 使用配置文件打包
npx rollup -c

# 直接打包
npx rollup src/main.js -o dist/bundle.js -f es

核心特性
#

  • 🌳 Tree-shaking:基于 ES modules 的静态分析,自动移除未使用的代码
  • 🗡️ 代码分割:支持多入口和动态导入,自动代码分割
  • 🌍 多种输出格式:ES、CJS、UMD、IIFE、AMD、SystemJS
  • 🔌 强大的插件系统:丰富的插件生态,易于扩展
  • 🎯 专注于库打包:适合打包 JavaScript 库和工具
  • 被 Vite 采用:Vite 在生产环境使用 Rollup 打包

为什么需要 Rollup
#

传统打包工具的问题
#

// ❌ Webpack 打包库的问题
// 1. 打包体积大(包含 runtime 代码)
// 2. 不够干净(模块包装代码多)
// 3. Tree-shaking 效果一般

// Webpack 打包输出(简化)
(function (modules) {
  // webpack runtime
  var installedModules = {};
  function __webpack_require__(moduleId) {
    // ...module loading code
  }
  return __webpack_require__(0);
})([
  /* 0 */ function (module, exports) {
    /* your code */
  },
  /* 1 */ function (module, exports) {
    /* dependencies */
  },
]);

// ❌ 问题:
// - 包含大量 webpack runtime 代码
// - 每个模块都被包装在函数中
// - 不适合作为库被其他项目引用

使用 Rollup 后
#

// ✅ Rollup 打包输出
// 几乎就是你的源代码,只是合并和优化了

// src/math.js
export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

// src/main.js
import { add } from "./math.js";
console.log(add(1, 2));

// Rollup 打包输出(ES format)
function add(a, b) {
  return a + b;
}

console.log(add(1, 2));

// ✅ 优势:
// - multiply 函数被 tree-shaking 移除(未使用)
// - 没有模块包装代码
// - 输出代码非常干净
// - 体积小,性能好

效果对比

# 同一个库,不同工具打包

# Webpack 打包
dist/bundle.js    15.2 KB

# Rollup 打包
dist/bundle.js    3.8 KB

# 差异原因:
# - Rollup 没有 runtime 代码
# - Rollup 的 tree-shaking 更彻底
# - Rollup 输出更接近源码

安装
#

基础安装
#

# 使用 npm
npm install -D rollup

# 使用 yarn
yarn add -D rollup

# 使用 pnpm(推荐)
pnpm add -D rollup

常用插件安装
#

# Node.js 解析插件(处理 node_modules)
pnpm add -D @rollup/plugin-node-resolve

# CommonJS 转换插件
pnpm add -D @rollup/plugin-commonjs

# Babel 插件(转换 ES6+)
pnpm add -D @rollup/plugin-babel

# TypeScript 插件
pnpm add -D @rollup/plugin-typescript

# JSON 插件
pnpm add -D @rollup/plugin-json

# Terser 压缩插件
pnpm add -D @rollup/plugin-terser

配置文件
#

基础配置
#

创建 rollup.config.js

// rollup.config.js
export default {
  input: "src/main.js",
  output: {
    file: "dist/bundle.js",
    format: "es",
  },
};

配置文件类型
#

// 1. 默认:rollup.config.js
export default {
  input: 'src/main.js',
  output: { file: 'dist/bundle.js', format: 'es' }
};

// 2. ESM:rollup.config.mjs
export default {
  input: 'src/main.js',
  output: { file: 'dist/bundle.js', format: 'es' }
};

// 3. CommonJS:rollup.config.cjs
module.exports = {
  input: 'src/main.js',
  output: { file: 'dist/bundle.js', format: 'es' }
};

// 4. TypeScript:rollup.config.ts
import { RollupOptions } from 'rollup';

const config: RollupOptions = {
  input: 'src/main.ts',
  output: { file: 'dist/bundle.js', format: 'es' }
};

export default config;

一、输入选项(Input Options)
#

1.1 input(入口文件)
#

作用:指定打包的入口文件。

// 单入口
export default {
  input: 'src/main.js'
};

// 多入口(对象形式)
export default {
  input: {
    main: 'src/main.js',
    vendor: 'src/vendor.js'
  }
};

// 多入口(数组形式)
export default {
  input: ['src/main.js', 'src/vendor.js']
};

影响对比

# 单入口
input: 'src/main.js'
→ 输出:dist/bundle.js

# 多入口(对象)
input: {
  main: 'src/main.js',
  vendor: 'src/vendor.js'
}
→ 输出:
  dist/main.js
  dist/vendor.js

# 多入口(数组)
input: ['src/main.js', 'src/vendor.js']
→ 输出:
  dist/main.js
  dist/vendor.js

1.2 external(外部依赖)
#

作用:指定哪些模块不打包进 bundle,而是作为外部依赖。

// 字符串数组
export default {
  input: 'src/main.js',
  external: ['lodash', 'vue']
};

// 正则表达式
export default {
  external: /node_modules/
};

// 函数
export default {
  external: (id) => {
    return id.includes('node_modules');
  }
};

影响对比

// 源码
import _ from 'lodash';
import { ref } from 'vue';

export function myFunction() {
  return _.debounce(() => {}, 100);
}

// 不配置 external
export default {
  input: 'src/main.js'
};
// 输出:lodash 和 vue 都被打包进去
// dist/bundle.js (200KB)

// 配置 external
export default {
  external: ['lodash', 'vue']
};
// 输出:lodash 和 vue 不打包,作为外部依赖
// dist/bundle.js (5KB)
import _ from 'lodash';
import { ref } from 'vue';

使用场景

// 打包库时(推荐)
export default {
  external: [
    'vue',           // 运行时依赖
    'lodash-es',     // 工具库依赖
    /^@vue\//        // Vue 相关包
  ]
};

// 打包应用时
export default {
  external: []  // 通常不需要 external
};

1.3 plugins(插件)
#

作用:配置 Rollup 插件。

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import babel from "@rollup/plugin-babel";
import terser from "@rollup/plugin-terser";

export default {
  input: "src/main.js",
  plugins: [
    resolve(), // 解析 node_modules
    commonjs(), // 转换 CommonJS
    babel({
      // 转换 ES6+
      babelHelpers: "bundled",
    }),
    terser(), // 压缩代码
  ],
};

插件执行顺序

export default {
  plugins: [
    // 1. 解析阶段(从上到下)
    resolve(), // 先解析模块路径
    commonjs(), // 再转换 CommonJS

    // 2. 转换阶段(从上到下)
    babel(), // 转换语法

    // 3. 生成阶段(从下到上)
    terser(), // 最后压缩
  ],
};

1.4 onwarn(警告处理)
#

作用:自定义警告处理。

export default {
  input: "src/main.js",
  onwarn(warning, warn) {
    // 忽略特定警告
    if (warning.code === "UNUSED_EXTERNAL_IMPORT") return;

    // 将警告转为错误
    if (warning.code === "CIRCULAR_DEPENDENCY") {
      throw new Error(warning.message);
    }

    // 默认处理
    warn(warning);
  },
};

常见警告类型

export default {
  onwarn(warning, warn) {
    // CIRCULAR_DEPENDENCY:循环依赖
    if (warning.code === "CIRCULAR_DEPENDENCY") {
      console.warn("检测到循环依赖:", warning.cycle);
      return;
    }

    // UNUSED_EXTERNAL_IMPORT:未使用的外部导入
    if (warning.code === "UNUSED_EXTERNAL_IMPORT") {
      return; // 忽略
    }

    // THIS_IS_UNDEFINED:this 为 undefined
    if (warning.code === "THIS_IS_UNDEFINED") {
      return;
    }

    warn(warning);
  },
};

1.5 treeshake(Tree-shaking)
#

作用:配置 tree-shaking 行为。

// 启用 tree-shaking(默认)
export default {
  treeshake: true
};

// 禁用 tree-shaking
export default {
  treeshake: false
};

// 使用预设
export default {
  treeshake: {
    preset: 'recommended'  // 'smallest' | 'safest' | 'recommended'
  }
};

// 详细配置
export default {
  treeshake: {
    preset: 'smallest',                        // 预设配置
    annotations: true,                         // 使用注释判断副作用
    correctVarValueBeforeDeclaration: false,   // 变量声明前的值优化
    moduleSideEffects: true,                   // 保留模块副作用
    propertyReadSideEffects: false,            // 属性读取无副作用
    tryCatchDeoptimization: true,              // try-catch 块优化
    unknownGlobalSideEffects: true             // 未知全局变量有副作用
  }
};

预设说明

预设说明适用场景
recommended推荐配置(默认)平衡体积和兼容性
smallest最激进的优化追求最小体积
safest最保守的优化确保兼容性

影响对比

// 源码
// utils.js
export function used() {
  console.log("used");
}

export function unused() {
  console.log("unused");
}

// main.js
import { used } from "./utils.js";
used();

// treeshake: true(默认)
function used() {
  console.log("used");
}
used();
// ✓ unused 函数被移除

// treeshake: false
function used() {
  console.log("used");
}
function unused() {
  console.log("unused");
}
used();
// ✗ unused 函数保留(未移除)

// treeshake: { preset: 'smallest' }
// 最激进的优化,移除更多未使用代码
function used() {
  console.log("used");
}
used();

二、输出选项(Output Options)
#

2.1 file / dir(输出文件)
#

作用:指定输出文件路径。

// 单个文件
export default {
  input: 'src/main.js',
  output: {
    file: 'dist/bundle.js'
  }
};

// 输出目录(多入口或代码分割)
export default {
  input: {
    main: 'src/main.js',
    vendor: 'src/vendor.js'
  },
  output: {
    dir: 'dist'
  }
};

规则

// ✅ 单入口 + file
{
  input: 'src/main.js',
  output: { file: 'dist/bundle.js' }
}

// ✅ 多入口 + dir
{
  input: ['src/a.js', 'src/b.js'],
  output: { dir: 'dist' }
}

// ❌ 单入口 + dir(不推荐)
{
  input: 'src/main.js',
  output: { dir: 'dist' }  // 会输出 dist/main.js
}

// ❌ 多入口 + file(错误)
{
  input: ['src/a.js', 'src/b.js'],
  output: { file: 'dist/bundle.js' }  // 报错
}

2.2 format(输出格式)
#

作用:指定输出的模块格式。

export default {
  output: {
    format: "es", // ES modules
  },
};

可选格式

格式说明使用场景
esES modules现代浏览器、Node.js、Vite
cjsCommonJSNode.js、旧版工具
umdUMD浏览器 <script>、Node.js
iife立即执行函数浏览器 <script>
amdAMDRequireJS
systemSystemJSSystemJS 加载器

输出对比

// 源码
export function add(a, b) {
  return a + b;
}

// format: 'es'
export function add(a, b) {
  return a + b;
}

// format: 'cjs'
Object.defineProperty(exports, "__esModule", { value: true });
function add(a, b) {
  return a + b;
}
exports.add = add;

// format: 'umd'
(function (global, factory) {
  typeof exports === "object" && typeof module !== "undefined"
    ? factory(exports)
    : typeof define === "function" && define.amd
      ? define(["exports"], factory)
      : ((global = global || self), factory((global.MyLib = {})));
})(this, function (exports) {
  function add(a, b) {
    return a + b;
  }
  exports.add = add;
});

// format: 'iife'
var MyLib = (function () {
  function add(a, b) {
    return a + b;
  }
  return { add: add };
})();

选择建议

// 打包库(多格式输出)
export default {
  input: 'src/main.js',
  output: [
    { file: 'dist/my-lib.esm.js', format: 'es' },      // 给打包工具用
    { file: 'dist/my-lib.cjs.js', format: 'cjs' },     // 给 Node.js 用
    { file: 'dist/my-lib.umd.js', format: 'umd', name: 'MyLib' }  // 给浏览器用
  ]
};

// 打包应用(单格式)
export default {
  input: 'src/main.js',
  output: {
    dir: 'dist',
    format: 'es'  // 现代应用使用 ES
  }
};

2.3 name(全局变量名)
#

作用:UMD/IIFE 格式的全局变量名。

export default {
  output: {
    format: "umd",
    name: "MyLibrary", // 必需
  },
};

影响对比

// format: 'umd', name: 'MyLib'
// 浏览器中可以通过 window.MyLib 访问

<script src="dist/bundle.js"></script>
<script>
  console.log(MyLib.add(1, 2));  // 3
</script>

// format: 'iife', name: 'MyLib'
var MyLib = (function () {
  // ...
}());

// format: 'es'(不需要 name)
export function add(a, b) {
  return a + b;
}

2.4 sourcemap(Source Map)
#

作用:生成 source map 文件。

export default {
  output: {
    sourcemap: true,
  },
};

可选值

// 生成独立的 .map 文件
{
  sourcemap: true;
}
// → dist/bundle.js
// → dist/bundle.js.map

// 内联 source map
{
  sourcemap: "inline";
}
// → dist/bundle.js(包含 source map)

// 隐藏的 source map
{
  sourcemap: "hidden";
}
// → dist/bundle.js(无注释)
// → dist/bundle.js.map

// 不生成
{
  sourcemap: false; // 默认
}

影响对比

# sourcemap: false
dist/bundle.js         50 KB

# sourcemap: true
dist/bundle.js         50 KB
dist/bundle.js.map    120 KB

# sourcemap: 'inline'
dist/bundle.js        170 KB(包含 source map)

2.5 globals(全局变量映射)
#

作用:指定外部依赖的全局变量名(UMD/IIFE)。

export default {
  external: ["vue", "lodash"],
  output: {
    format: "umd",
    name: "MyLib",
    globals: {
      vue: "Vue",
      lodash: "_",
    },
  },
};

影响对比

// 源码
import { ref } from 'vue';
import _ from 'lodash';

// 不配置 globals(错误)
export default {
  external: ['vue', 'lodash'],
  output: { format: 'umd', name: 'MyLib' }
};
// ❌ 报错:缺少全局变量映射

// 配置 globals(正确)
export default {
  external: ['vue', 'lodash'],
  output: {
    format: 'umd',
    name: 'MyLib',
    globals: {
      vue: 'Vue',
      lodash: '_'
    }
  }
};

// 输出
(function (global, Vue, _) {
  // ...
}(this, window.Vue, window._));

2.6 exports(导出模式)
#

作用:指定导出模式。

export default {
  output: {
    exports: "auto", // 默认
  },
};

可选值

说明适用场景
auto自动检测默认(推荐)
default仅默认导出单一默认导出 export default
named仅命名导出多个命名导出 export { a, b }
none无导出IIFE 格式,不导出任何内容

影响对比

// 源码 1:仅默认导出
export default 42;

// exports: 'auto' 或 'default'(CJS 输出)
module.exports = 42;

// exports: 'named'(CJS 输出)
Object.defineProperty(exports, '__esModule', { value: true });
exports.default = 42;

// 源码 2:混合导出
export default function main() {}
export const util = {};

// exports: 'auto'(CJS 输出)
Object.defineProperty(exports, '__esModule', { value: true });
exports.default = main;
exports.util = util;

// exports: 'default'(CJS 输出)
module.exports = main;  // 只导出默认值,util 被忽略

// exports: 'named'(CJS 输出)
Object.defineProperty(exports, '__esModule', { value: true });
exports.default = main;
exports.util = util;

2.7 banner / footer(注释)
#

作用:在输出文件头部/尾部添加注释。

export default {
  output: {
    banner: "/* MyLib v1.0.0 - MIT License */",
    footer: "/* Built on 2025-11-14 */",
  },
};

动态注释

import pkg from "./package.json";

export default {
  output: {
    banner: `/*!
 * ${pkg.name} v${pkg.version}
 * (c) 2025 ${pkg.author}
 * @license ${pkg.license}
 */`,
    footer: `/* Built: ${new Date().toISOString()} */`,
  },
};

输出

/*!
 * my-lib v1.0.0
 * (c) 2025 John Doe
 * @license MIT
 */
function add(a, b) {
  return a + b;
}
export { add };
/* Built: 2025-11-14T10:30:00.000Z */

2.8 compact(压缩输出)
#

作用:压缩输出代码(移除空格和换行)。

export default {
  output: {
    compact: true,
  },
};

影响对比

// compact: false(默认)
function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

export { add, multiply };

// compact: true
function add(a, b) {
  return a + b;
}
function multiply(a, b) {
  return a * b;
}
export { add, multiply };

注意

// compact 只移除空格,不混淆代码
// 如需完整压缩,使用 terser 插件

import terser from "@rollup/plugin-terser";

export default {
  plugins: [terser()],
};

2.9 entryFileNames / chunkFileNames(文件命名)
#

作用:自定义输出文件名。

export default {
  output: {
    dir: "dist",
    entryFileNames: "[name].[hash].js", // 入口文件
    chunkFileNames: "chunks/[name].[hash].js", // 代码分割文件
    assetFileNames: "assets/[name].[hash][extname]", // 资源文件
  },
};

占位符

占位符说明示例适用
[name]文件名(不含扩展名)main全部
[hash]内容哈希(完整)abc123def456全部
[chunkhash]仅 chunk 内容哈希abc123chunk/entry
[format]输出格式es, cjsentry/chunk
[ext]扩展名(不带点)js全部
[extname]扩展名(带点).js全部

示例

export default {
  input: {
    main: 'src/main.js',
    vendor: 'src/vendor.js'
  },
  output: {
    dir: 'dist',
    entryFileNames: 'js/[name].[hash].js',
    chunkFileNames: 'js/chunks/[name].[hash].js',
    assetFileNames: 'assets/[name].[hash][extname]'
  }
};

// 输出
dist/
├── js/
   ├── main.abc123def456.js
   ├── vendor.def456ghi789.js
   └── chunks/
       └── shared.ghi789jkl012.js
└── assets/
    └── logo.jkl012mno345.png

// 使用函数动态命名
export default {
  output: {
    dir: 'dist',
    entryFileNames: (chunkInfo) => {
      return chunkInfo.name === 'main'
        ? 'app.js'
        : '[name]-[hash].js';
    },
    chunkFileNames: (chunkInfo) => {
      // 根据模块来源分组
      if (chunkInfo.moduleIds.some(id => id.includes('node_modules'))) {
        return 'vendor/[name].[hash].js';
      }
      return 'chunks/[name].[hash].js';
    }
  }
};

2.10 preserveModules(保留模块结构)
#

作用:保留原始模块结构,不合并文件。

export default {
  input: ["src/main.js", "src/utils.js"],
  output: {
    dir: "dist",
    format: "es",
    preserveModules: true, // 保留模块结构
    preserveModulesRoot: "src", // 指定根目录
  },
};

影响对比

# preserveModules: false(默认)
dist/
└── main.js(所有代码合并)

# preserveModules: true
dist/
├── main.js
├── utils.js
└── components/
    ├── Button.js
    └── Input.js

适用场景

// 适合发布库时保留模块结构
// 用户可以按需导入
import { Button } from "my-lib/components/Button";
import { formatDate } from "my-lib/utils/date";

2.11 manualChunks(手动代码分割)
#

作用:手动控制代码分割。

export default {
  output: {
    dir: 'dist',
    manualChunks: {
      vendor: ['react', 'react-dom'],
      utils: ['lodash', 'axios']
    }
  }
};

// 或使用函数
export default {
  output: {
    dir: 'dist',
    manualChunks(id) {
      // 将 node_modules 分离到 vendor
      if (id.includes('node_modules')) {
        return 'vendor';
      }
      // 将 utils 目录分离
      if (id.includes('src/utils')) {
        return 'utils';
      }
    }
  }
};

输出结果

dist/
├── main.js
├── vendor.js      # react, react-dom
└── utils.js       # lodash, axios

2.12 interop(互操作性)
#

作用:控制 ES modules 和 CommonJS 的互操作方式。

export default {
  output: {
    format: "cjs",
    interop: "auto", // 'auto' | 'esModule' | 'default' | 'defaultOnly' | false
  },
};

可选值

说明使用场景
auto自动检测(默认)推荐
esModule添加 __esModule 标记标准 ES module 互操作
default使用 default 互操作仅有默认导出
defaultOnly仅处理 default 导出优化场景
false不处理互操作纯 ES modules

三、常用插件
#

3.1 @rollup/plugin-node-resolve
#

作用:解析 node_modules 中的模块。

pnpm add -D @rollup/plugin-node-resolve
import resolve from "@rollup/plugin-node-resolve";

export default {
  plugins: [
    resolve({
      extensions: [".js", ".ts"], // 支持的扩展名
      browser: true, // 使用 browser 字段
      preferBuiltins: false, // 优先使用内置模块
    }),
  ],
};

影响对比

// 源码
import _ from "lodash-es";

// 不使用 resolve 插件
// ❌ 报错:无法解析 'lodash-es'

// 使用 resolve 插件
// ✓ 自动从 node_modules 解析并打包

3.2 @rollup/plugin-commonjs
#

作用:将 CommonJS 模块转换为 ES modules。

pnpm add -D @rollup/plugin-commonjs
import commonjs from "@rollup/plugin-commonjs";

export default {
  plugins: [
    commonjs({
      include: "node_modules/**", // 包含的文件
      exclude: [], // 排除的文件
      extensions: [".js", ".cjs"], // 支持的扩展名
    }),
  ],
};

影响对比

// CommonJS 模块(node_modules/some-lib/index.js)
module.exports = function someLib() {
  return "hello";
};

// 不使用 commonjs 插件
import someLib from "some-lib";
// ❌ 无法正确导入 CommonJS 模块

// 使用 commonjs 插件
import someLib from "some-lib";
someLib(); // ✓ 正常工作

3.3 @rollup/plugin-babel
#

作用:使用 Babel 转换代码。

pnpm add -D @rollup/plugin-babel @babel/core @babel/preset-env
import babel from "@rollup/plugin-babel";

export default {
  plugins: [
    babel({
      babelHelpers: "bundled", // 'bundled' | 'runtime' | 'inline' | 'external'
      exclude: "node_modules/**",
      extensions: [".js", ".ts", ".jsx", ".tsx"],
      presets: [["@babel/preset-env", { targets: { node: "current" } }]],
    }),
  ],
};

babelHelpers 选项

// babelHelpers: 'bundled'(推荐用于库)
// Babel helpers 打包进输出文件

// babelHelpers: 'runtime'(用于应用)
// 需要安装 @babel/runtime
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";

// babelHelpers: 'inline'(不推荐)
// 每个文件都内联 helpers,导致代码重复

// babelHelpers: 'external'(用于工具库)
// helpers 作为外部依赖

3.4 @rollup/plugin-typescript
#

作用:处理 TypeScript 文件。

pnpm add -D @rollup/plugin-typescript typescript tslib
import typescript from "@rollup/plugin-typescript";

export default {
  input: "src/main.ts",
  plugins: [
    typescript({
      tsconfig: "./tsconfig.json", // tsconfig 路径
      declaration: true, // 生成 .d.ts
      declarationDir: "dist/types", // .d.ts 输出目录
      exclude: ["**/*.test.ts"], // 排除文件
    }),
  ],
};

生成类型声明

// src/math.ts
export function add(a: number, b: number): number {
  return a + b;
}

// 输出
// dist/math.js
export function add(a, b) {
  return a + b;
}

// dist/types/math.d.ts
export declare function add(a: number, b: number): number;

3.5 @rollup/plugin-json
#

作用:导入 JSON 文件。

pnpm add -D @rollup/plugin-json
import json from "@rollup/plugin-json";

export default {
  plugins: [
    json({
      compact: true, // 压缩 JSON
      namedExports: true, // 支持命名导出
    }),
  ],
};

使用示例

// package.json
{
  "name": "my-lib",
  "version": "1.0.0"
}

// 源码
import pkg from './package.json';
import { version } from './package.json';

console.log(pkg.name);     // 'my-lib'
console.log(version);      // '1.0.0'

3.6 @rollup/plugin-terser
#

作用:压缩 JavaScript 代码。

pnpm add -D @rollup/plugin-terser
import terser from "@rollup/plugin-terser";

export default {
  plugins: [
    terser({
      compress: {
        drop_console: true, // 移除 console
        drop_debugger: true, // 移除 debugger
        pure_funcs: ["console.log"], // 移除特定函数调用
      },
      format: {
        comments: false, // 移除注释
      },
    }),
  ],
};

压缩效果

// 源码
function add(a, b) {
  console.log("Adding:", a, b);
  return a + b;
}

export { add };

// terser 压缩后
function add(a, b) {
  return a + b;
}
export { add };

// 体积对比
// 源码:120 bytes
// 压缩后:35 bytes(减少 70%)

3.7 @rollup/plugin-replace
#

作用:替换代码中的字符串。

pnpm add -D @rollup/plugin-replace
import replace from "@rollup/plugin-replace";

export default {
  plugins: [
    replace({
      "process.env.NODE_ENV": JSON.stringify("production"),
      __VERSION__: JSON.stringify(require("./package.json").version),
      preventAssignment: true, // 防止意外替换赋值语句
    }),
  ],
};

使用示例

// 源码
if (process.env.NODE_ENV === "development") {
  console.log("Debug mode");
}

console.log("Version:", __VERSION__);

// 替换后
if ("production" === "development") {
  console.log("Debug mode"); // tree-shaking 会移除这段代码
}

console.log("Version:", "1.0.0");

3.8 rollup-plugin-visualizer
#

作用:生成打包分析报告。

pnpm add -D rollup-plugin-visualizer
import { visualizer } from "rollup-plugin-visualizer";

export default {
  plugins: [
    visualizer({
      filename: "stats.html", // 输出文件名
      open: true, // 自动打开浏览器
      gzipSize: true, // 显示 gzip 大小
      brotliSize: true, // 显示 brotli 大小
      template: "treemap", // 'treemap' | 'sunburst' | 'network'
    }),
  ],
};

生成报告

npx rollup -c

# 输出
# stats.html(可视化分析报告)
# - 各模块大小占比
# - 依赖关系图
# - gzip/brotli 压缩大小
# - 模块依赖树状图

3.9 @rollup/plugin-alias
#

作用:配置模块路径别名。

pnpm add -D @rollup/plugin-alias
import alias from "@rollup/plugin-alias";
import { fileURLToPath } from "url";

export default {
  plugins: [
    alias({
      entries: [
        {
          find: "@",
          replacement: fileURLToPath(new URL("./src", import.meta.url)),
        },
        {
          find: "@components",
          replacement: fileURLToPath(
            new URL("./src/components", import.meta.url),
          ),
        },
        {
          find: "@utils",
          replacement: fileURLToPath(new URL("./src/utils", import.meta.url)),
        },
      ],
    }),
  ],
};

使用示例

// 使用别名前
import Button from "../../../components/Button.vue";
import { formatDate } from "../../../utils/date.js";

// 使用别名后
import Button from "@components/Button.vue";
import { formatDate } from "@utils/date.js";

四、完整推荐配置
#

4.1 打包 JavaScript 库
#

// rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import babel from "@rollup/plugin-babel";
import terser from "@rollup/plugin-terser";
import pkg from "./package.json";

export default [
  // ES module
  {
    input: "src/index.js",
    external: Object.keys(pkg.peerDependencies || {}),
    output: {
      file: pkg.module,
      format: "es",
      sourcemap: true,
    },
    plugins: [
      resolve(),
      commonjs(),
      babel({
        babelHelpers: "bundled",
        exclude: "node_modules/**",
      }),
    ],
  },

  // CommonJS
  {
    input: "src/index.js",
    external: Object.keys(pkg.peerDependencies || {}),
    output: {
      file: pkg.main,
      format: "cjs",
      sourcemap: true,
      exports: "auto",
    },
    plugins: [
      resolve(),
      commonjs(),
      babel({
        babelHelpers: "bundled",
        exclude: "node_modules/**",
      }),
    ],
  },

  // UMD(浏览器)
  {
    input: "src/index.js",
    external: Object.keys(pkg.peerDependencies || {}),
    output: {
      file: pkg.browser,
      format: "umd",
      name: "MyLib",
      sourcemap: true,
      globals: {
        vue: "Vue", // 外部依赖的全局变量
      },
    },
    plugins: [
      resolve({ browser: true }),
      commonjs(),
      babel({
        babelHelpers: "bundled",
        exclude: "node_modules/**",
      }),
      terser(), // 压缩
    ],
  },
];

4.2 打包 TypeScript 库
#

// rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import terser from "@rollup/plugin-terser";
import pkg from "./package.json";

export default [
  // ES module
  {
    input: "src/index.ts",
    external: Object.keys(pkg.peerDependencies || {}),
    output: {
      file: pkg.module,
      format: "es",
      sourcemap: true,
    },
    plugins: [
      resolve(),
      commonjs(),
      typescript({
        tsconfig: "./tsconfig.json",
        declaration: true,
        declarationDir: "dist/types",
      }),
    ],
  },

  // CommonJS
  {
    input: "src/index.ts",
    external: Object.keys(pkg.peerDependencies || {}),
    output: {
      file: pkg.main,
      format: "cjs",
      sourcemap: true,
      exports: "auto",
    },
    plugins: [
      resolve(),
      commonjs(),
      typescript({
        tsconfig: "./tsconfig.json",
        declaration: false, // 只在 ES 输出时生成一次
      }),
    ],
  },

  // UMD(压缩版)
  {
    input: "src/index.ts",
    external: Object.keys(pkg.peerDependencies || {}),
    output: {
      file: "dist/my-lib.umd.min.js",
      format: "umd",
      name: "MyLib",
      sourcemap: true,
      globals: {
        vue: "Vue",
      },
    },
    plugins: [
      resolve({ browser: true }),
      commonjs(),
      typescript({
        tsconfig: "./tsconfig.json",
        declaration: false,
      }),
      terser(),
    ],
  },
];

对应的 package.json

{
  "name": "my-lib",
  "version": "1.0.0",
  "type": "module",
  "main": "dist/my-lib.cjs.js",
  "module": "dist/my-lib.esm.js",
  "browser": "dist/my-lib.umd.min.js",
  "types": "dist/types/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/types/index.d.ts",
      "import": "./dist/my-lib.esm.js",
      "require": "./dist/my-lib.cjs.js"
    }
  },
  "files": ["dist"],
  "scripts": {
    "build": "rollup -c"
  }
}

4.3 打包 Vue 3 组件库
#

// rollup.config.js
import vue from "rollup-plugin-vue";
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import postcss from "rollup-plugin-postcss";
import terser from "@rollup/plugin-terser";
import pkg from "./package.json";

export default [
  {
    input: "src/index.ts",
    external: ["vue"],
    output: [
      {
        file: pkg.module,
        format: "es",
        sourcemap: true,
      },
      {
        file: pkg.main,
        format: "cjs",
        sourcemap: true,
        exports: "named",
      },
    ],
    plugins: [
      resolve(),
      commonjs(),
      vue({
        target: "browser",
        preprocessStyles: true,
      }),
      typescript({
        tsconfig: "./tsconfig.json",
        declaration: true,
        declarationDir: "dist/types",
      }),
      postcss({
        extract: true,
        minimize: true,
      }),
      terser(),
    ],
  },
];

4.4 Monorepo 子包配置
#

// packages/shared/rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";

export default {
  input: "src/index.ts",
  external: ["vue"], // 不打包 peerDependencies
  output: [
    {
      file: "dist/index.esm.js",
      format: "es",
      sourcemap: true,
    },
    {
      file: "dist/index.cjs.js",
      format: "cjs",
      sourcemap: true,
      exports: "named",
    },
  ],
  plugins: [
    resolve(),
    typescript({
      tsconfig: "./tsconfig.json",
      declaration: true,
      declarationDir: "dist/types",
      rootDir: "src",
    }),
  ],
};

五、Watch 模式(监听模式)
#

5.1 基础配置
#

export default {
  input: "src/main.js",
  output: {
    file: "dist/bundle.js",
    format: "es",
  },
  watch: {
    include: "src/**", // 监听的文件
    exclude: "node_modules/**", // 排除的文件
    clearScreen: false, // 不清空控制台
  },
};

5.2 Watch 选项
#

export default {
  // ...
  watch: {
    buildDelay: 1000, // 延迟构建(ms)
    chokidar: {
      // chokidar 选项
      usePolling: true, // 使用轮询(某些系统需要)
      interval: 100, // 轮询间隔(ms)
    },
    clearScreen: false, // 不清空屏幕
    skipWrite: false, // 不跳过写入
    include: ["src/**"], // 包含的文件
    exclude: ["node_modules/**"], // 排除的文件
  },
};

5.3 使用 Watch 模式
#

# 命令行
npx rollup -c -w
# 或
npx rollup -c --watch

# package.json
{
  "scripts": {
    "dev": "rollup -c -w",
    "build": "rollup -c"
  }
}

5.4 编程式 Watch
#

import { watch } from "rollup";

const watchOptions = {
  input: "src/main.js",
  output: {
    file: "dist/bundle.js",
    format: "es",
  },
  watch: {
    include: "src/**",
  },
};

const watcher = watch(watchOptions);

watcher.on("event", (event) => {
  switch (event.code) {
    case "START":
      console.log("Rollup is starting...");
      break;
    case "BUNDLE_START":
      console.log("Building bundle...");
      break;
    case "BUNDLE_END":
      console.log("Bundle built in", event.duration, "ms");
      break;
    case "END":
      console.log("Watching for changes...");
      break;
    case "ERROR":
      console.error("Error:", event.error);
      break;
  }
});

// 停止监听
// watcher.close();

六、性能优化
#

6.1 缓存配置
#

export default {
  cache: true, // 启用缓存
  // ...
};

// 编程式使用缓存
let cache;

async function build() {
  const bundle = await rollup({
    input: "src/main.js",
    cache, // 使用之前的缓存
  });

  cache = bundle.cache; // 保存缓存供下次使用
}

6.2 并行处理
#

export default {
  maxParallelFileOps: 20, // 最大并行文件操作数(默认 20)
};

6.3 优化插件顺序
#

export default {
  plugins: [
    // 1. 首先解析路径
    resolve(),

    // 2. 转换 CommonJS
    commonjs(),

    // 3. 转换代码
    typescript(),

    // 4. 压缩(最后)
    terser(),
  ],
};

6.4 使用 external 减少打包体积
#

import pkg from "./package.json";

export default {
  external: [
    // 不打包依赖
    ...Object.keys(pkg.dependencies || {}),
    ...Object.keys(pkg.peerDependencies || {}),

    // 不打包 Node.js 内置模块
    /^node:/,
    "path",
    "fs",
    "url",
  ],
};

七、常见问题
#

7.1 如何处理 CSS
#

方案一:使用 rollup-plugin-postcss

pnpm add -D rollup-plugin-postcss
import postcss from "rollup-plugin-postcss";

export default {
  plugins: [
    postcss({
      extract: true, // 提取到单独文件
      minimize: true, // 压缩
      modules: false, // CSS Modules
      extensions: [".css", ".scss"],
    }),
  ],
};

方案二:外部引入

// 在组件中引入
import "./styles.css";

// rollup.config.js
export default {
  plugins: [
    postcss({
      inject: true, // 注入到 <head>
    }),
  ],
};

7.2 循环依赖警告
#

问题

(!) Circular dependency
src/a.js -> src/b.js -> src/a.js

解决方案

// ❌ 循环依赖
// a.js
import { b } from "./b.js";
export const a = b + 1;

// b.js
import { a } from "./a.js";
export const b = a + 1;

// ✅ 解决方案 1:重构代码
// shared.js
export const value = 1;

// a.js
import { value } from "./shared.js";
export const a = value + 1;

// b.js
import { value } from "./shared.js";
export const b = value + 2;

// ✅ 解决方案 2:忽略警告(不推荐)
export default {
  onwarn(warning, warn) {
    if (warning.code === "CIRCULAR_DEPENDENCY") return;
    warn(warning);
  },
};

7.3 未使用的外部导入
#

问题

(!) Unused external import 'lodash'

原因

// 导入了但没使用
import _ from "lodash";

// main.js
export function add(a, b) {
  return a + b;
}

解决方案

// 移除未使用的导入
// import _ from 'lodash';  // 删除

export function add(a, b) {
  return a + b;
}

7.4 this is undefined
#

问题

(!) `this` has been rewritten to `undefined`

原因:ES modules 中 thisundefined

解决方案

// ❌ 使用 this
export function getGlobal() {
  return this.window;
}

// ✅ 使用 globalThis
export function getGlobal() {
  return globalThis.window;
}

// ✅ 使用 window
export function getGlobal() {
  return window;
}

7.5 打包体积过大
#

问题:打包后的文件太大。

解决方案

// 1. 配置 external(不打包依赖)
export default {
  external: ['vue', 'lodash-es']
};

// 2. 启用 tree-shaking
export default {
  treeshake: true
};

// 3. 使用压缩
import terser from '@rollup/plugin-terser';

export default {
  plugins: [terser()]
};

// 4. 代码分割
export default {
  input: {
    main: 'src/main.js',
    vendor: 'src/vendor.js'
  },
  output: {
    dir: 'dist',
    format: 'es'
  }
};

// 5. 分析打包
import { visualizer } from 'rollup-plugin-visualizer';

export default {
  plugins: [
    visualizer({ open: true })
  ]
};

7.6 处理环境变量
#

问题:如何在代码中使用环境变量?

方案一:使用 @rollup/plugin-replace

import replace from "@rollup/plugin-replace";

export default {
  plugins: [
    replace({
      "process.env.NODE_ENV": JSON.stringify(
        process.env.NODE_ENV || "production",
      ),
      "process.env.API_URL": JSON.stringify(process.env.API_URL),
      preventAssignment: true,
    }),
  ],
};

方案二:使用 dotenv

import dotenv from "dotenv";
import replace from "@rollup/plugin-replace";

dotenv.config();

export default {
  plugins: [
    replace({
      "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
      "process.env.API_URL": JSON.stringify(process.env.API_URL),
      "process.env.API_KEY": JSON.stringify(process.env.API_KEY),
      preventAssignment: true,
    }),
  ],
};

7.7 TypeScript 路径映射问题
#

问题:TypeScript 的 paths 配置不生效。

解决方案

# 安装插件
pnpm add -D @rollup/plugin-alias
// rollup.config.js
import alias from "@rollup/plugin-alias";
import { fileURLToPath } from "url";

export default {
  plugins: [
    alias({
      entries: [
        {
          find: "@",
          replacement: fileURLToPath(new URL("./src", import.meta.url)),
        },
      ],
    }),
    typescript(),
  ],
};
// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

八、最佳实践
#

8.1 多格式输出
#

// 为不同场景提供不同格式
export default [
  // ES(现代打包工具)
  {
    output: { format: "es" },
  },
  // CJS(Node.js)
  {
    output: { format: "cjs" },
  },
  // UMD(浏览器)
  {
    output: { format: "umd", name: "MyLib" },
  },
];

8.2 正确配置 external
#

import pkg from "./package.json";

export default {
  // 运行时依赖不打包
  external: [
    ...Object.keys(pkg.dependencies || {}),
    ...Object.keys(pkg.peerDependencies || {}),
    /^node:/, // Node.js 内置模块
  ],
};

8.3 生成 Source Map
#

export default {
  output: {
    sourcemap: true, // 方便调试
  },
};

8.4 生成类型声明
#

import typescript from "@rollup/plugin-typescript";

export default {
  plugins: [
    typescript({
      declaration: true,
      declarationDir: "dist/types",
    }),
  ],
};

8.5 配置 package.json
#

{
  "type": "module",
  "main": "dist/index.cjs.js",
  "module": "dist/index.esm.js",
  "types": "dist/types/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/types/index.d.ts",
      "import": "./dist/index.esm.js",
      "require": "./dist/index.cjs.js"
    }
  },
  "files": ["dist"],
  "sideEffects": false
}

8.6 使用 NPM Scripts
#

{
  "scripts": {
    "build": "rollup -c",
    "build:watch": "rollup -c -w",
    "build:prod": "NODE_ENV=production rollup -c",
    "build:analyze": "rollup -c --environment ANALYZE:true"
  }
}

8.7 日志和调试
#

export default {
  // 配置日志级别
  logLevel: "info", // 'silent' | 'error' | 'warn' | 'info' | 'debug'

  // 自定义日志处理
  onLog(level, log, handler) {
    if (log.code === "CIRCULAR_DEPENDENCY") {
      return; // 忽略循环依赖警告
    }
    if (level === "warn") {
      console.warn("警告:", log.message);
    }
    handler(level, log);
  },

  // 自定义警告处理(已弃用,使用 onLog)
  onwarn(warning, warn) {
    if (warning.code === "UNUSED_EXTERNAL_IMPORT") return;
    warn(warning);
  },
};

8.8 条件配置
#

// rollup.config.js
import { defineConfig } from "rollup";

const isProduction = process.env.NODE_ENV === "production";
const shouldAnalyze = process.env.ANALYZE === "true";

export default defineConfig({
  input: "src/main.js",
  output: {
    dir: "dist",
    format: "es",
    sourcemap: !isProduction, // 只在开发环境生成 sourcemap
  },
  plugins: [
    resolve(),
    commonjs(),
    typescript(),
    isProduction && terser(), // 只在生产环境压缩
    shouldAnalyze && visualizer(), // 按需分析
  ].filter(Boolean), // 过滤掉 false 值
});

8.9 使用 defineConfig 获得类型提示
#

// rollup.config.js
import { defineConfig } from 'rollup';
import typescript from '@rollup/plugin-typescript';

export default defineConfig({
  input: 'src/main.ts',
  output: {
    file: 'dist/bundle.js',
    format: 'es'
  },
  plugins: [typescript()]
});

// 或使用 JSDoc
/** @type {import('rollup').RollupOptions} */
export default {
  input: 'src/main.js',
  output: {
    file: 'dist/bundle.js',
    format: 'es'
  }
};

8.10 Monorepo 中的配置共享
#

// packages/shared/rollup.config.base.js
export function createConfig(input, output) {
  return {
    input,
    output,
    external: ['vue', 'react'],
    plugins: [
      resolve(),
      commonjs(),
      typescript()
    ]
  };
}

// packages/package-a/rollup.config.js
import { createConfig } from '../shared/rollup.config.base.js';

export default createConfig('src/index.ts', {
  file: 'dist/index.js',
  format: 'es'
});

// packages/package-b/rollup.config.js
import { createConfig } from '../shared/rollup.config.base.js';

export default createConfig('src/index.ts', {
  file: 'dist/index.js',
  format: 'es'
});

8.11 错误处理和恢复
#

// rollup.config.js
export default {
  input: "src/main.js",
  output: {
    file: "dist/bundle.js",
    format: "es",
  },
  onLog(level, log, handler) {
    // 记录所有错误
    if (level === "error") {
      console.error("构建错误:", log);
    }
    handler(level, log);
  },
  plugins: [
    {
      name: "error-handler",
      buildEnd(error) {
        if (error) {
          console.error("构建失败:", error);
          // 发送通知、记录日志等
        }
      },
    },
  ],
};

// 编程式错误处理
import { rollup } from "rollup";

async function build() {
  try {
    const bundle = await rollup({
      input: "src/main.js",
    });

    await bundle.write({
      file: "dist/bundle.js",
      format: "es",
    });

    console.log("✅ 构建成功");
  } catch (error) {
    console.error("❌ 构建失败:", error.message);
    if (error.loc) {
      console.error(
        `  位置: ${error.loc.file}:${error.loc.line}:${error.loc.column}`,
      );
    }
    process.exit(1);
  }
}

build();

8.12 性能监控
#

export default {
  input: "src/main.js",
  output: {
    file: "dist/bundle.js",
    format: "es",
  },
  // 启用性能分析
  perf: true,
  plugins: [
    {
      name: "perf-monitor",
      buildStart() {
        this.startTime = Date.now();
        console.log("🚀 开始构建...");
      },
      buildEnd() {
        const duration = Date.now() - this.startTime;
        console.log(`✅ 构建完成,耗时: ${duration}ms`);
      },
      renderStart() {
        console.log("📝 开始生成代码...");
      },
      renderEnd() {
        console.log("✅ 代码生成完成");
      },
    },
  ],
};

8.13 自定义插件示例
#

// rollup.config.js

// 简单的横幅插件
function bannerPlugin(text) {
  return {
    name: "banner",
    renderChunk(code) {
      return `/* ${text} */\n${code}`;
    },
  };
}

// 文件大小报告插件
function sizeReportPlugin() {
  return {
    name: "size-report",
    generateBundle(options, bundle) {
      console.log("\n📊 文件大小报告:");
      for (const [fileName, chunk] of Object.entries(bundle)) {
        if (chunk.type === "chunk") {
          const size = (chunk.code.length / 1024).toFixed(2);
          console.log(`  ${fileName}: ${size} KB`);
        }
      }
    },
  };
}

export default {
  input: "src/main.js",
  output: {
    file: "dist/bundle.js",
    format: "es",
  },
  plugins: [bannerPlugin("My Library v1.0.0"), sizeReportPlugin()],
};

九、与其他工具对比
#

Rollup vs Webpack
#

特性RollupWebpack
打包目标应用
输出体积⭐⭐⭐⭐⭐ 小⭐⭐⭐ 中等
Tree-shaking⭐⭐⭐⭐⭐ 优秀⭐⭐⭐⭐ 良好
代码分割⭐⭐⭐⭐ 简单⭐⭐⭐⭐⭐ 强大
插件生态⭐⭐⭐⭐ 丰富⭐⭐⭐⭐⭐ 最丰富
学习曲线⭐⭐ 简单⭐⭐⭐⭐ 复杂
开发服务器❌ 无✅ 有

选择建议

打包库 → Rollup ⭐⭐⭐⭐⭐
- 输出干净
- 体积小
- Tree-shaking 好

打包应用 → Webpack ⭐⭐⭐⭐
- 功能全面
- 开发体验好
- 生态完善

Rollup vs esbuild
#

特性Rollupesbuild
速度⭐⭐⭐ 快⭐⭐⭐⭐⭐ 极快
插件生态⭐⭐⭐⭐ 丰富⭐⭐ 有限
Tree-shaking⭐⭐⭐⭐⭐ 优秀⭐⭐⭐ 基础
代码转换⭐⭐⭐⭐ Babel⭐⭐⭐ 内置
生产环境✅ 成熟⚠️ 快速发展中

选择建议

生产级库打包 → Rollup ⭐⭐⭐⭐⭐
- Tree-shaking 最好
- 输出质量高
- 生态成熟

快速开发 → esbuild ⭐⭐⭐⭐
- 速度极快
- 适合开发环境
- 简单场景

Rollup vs Vite
#

Vite = esbuild(开发) + Rollup(生产)

开发阶段:
- Vite 使用 esbuild 预构建
- 原生 ES modules

生产阶段:
- Vite 使用 Rollup 打包
- Tree-shaking + 代码分割

Rollup 在 Vite 中的作用

// vite.config.js
export default {
  build: {
    // 这些都是 Rollup 选项
    rollupOptions: {
      external: ["vue"],
      output: {
        globals: {
          vue: "Vue",
        },
      },
    },
  },
};

十、快速配置模板
#

10.1 纯 JavaScript 库
#

// rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import terser from "@rollup/plugin-terser";

export default [
  // ES Module
  {
    input: "src/index.js",
    output: {
      file: "dist/index.esm.js",
      format: "es",
      sourcemap: true,
    },
    external: ["vue", "react"],
    plugins: [resolve(), commonjs()],
  },
  // CommonJS
  {
    input: "src/index.js",
    output: {
      file: "dist/index.cjs.js",
      format: "cjs",
      sourcemap: true,
      exports: "auto",
    },
    external: ["vue", "react"],
    plugins: [resolve(), commonjs()],
  },
  // UMD(压缩)
  {
    input: "src/index.js",
    output: {
      file: "dist/index.umd.min.js",
      format: "umd",
      name: "MyLib",
      sourcemap: true,
      globals: { vue: "Vue", react: "React" },
    },
    external: ["vue", "react"],
    plugins: [resolve(), commonjs(), terser()],
  },
];

10.2 TypeScript 库
#

// rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import terser from "@rollup/plugin-terser";
import { defineConfig } from "rollup";

export default defineConfig([
  {
    input: "src/index.ts",
    output: [
      { file: "dist/index.esm.js", format: "es", sourcemap: true },
      {
        file: "dist/index.cjs.js",
        format: "cjs",
        sourcemap: true,
        exports: "auto",
      },
    ],
    external: ["vue"],
    plugins: [
      resolve(),
      commonjs(),
      typescript({
        declaration: true,
        declarationDir: "dist/types",
        rootDir: "src",
      }),
    ],
  },
  {
    input: "src/index.ts",
    output: {
      file: "dist/index.umd.min.js",
      format: "umd",
      name: "MyLib",
      sourcemap: true,
      globals: { vue: "Vue" },
    },
    external: ["vue"],
    plugins: [resolve(), commonjs(), typescript(), terser()],
  },
]);

10.3 Vue 3 组件库
#

// rollup.config.js
import vue from "rollup-plugin-vue";
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import postcss from "rollup-plugin-postcss";
import { defineConfig } from "rollup";

export default defineConfig({
  input: "src/index.ts",
  output: [
    { file: "dist/index.esm.js", format: "es", sourcemap: true },
    {
      file: "dist/index.cjs.js",
      format: "cjs",
      sourcemap: true,
      exports: "named",
    },
  ],
  external: ["vue"],
  plugins: [
    resolve(),
    commonjs(),
    vue({ target: "browser", preprocessStyles: true }),
    typescript({ declaration: true, declarationDir: "dist/types" }),
    postcss({ extract: true, minimize: true }),
  ],
});

十一、总结
#

核心优势
#

  1. 输出干净:接近源码的输出,无冗余代码
  2. Tree-shaking:业界最好的无用代码消除
  3. 多格式支持:ES/CJS/UMD/IIFE/AMD/System
  4. 专注库打包:适合打包 JavaScript 库和工具
  5. 插件丰富:强大的插件生态系统
  6. 配置简单:相比 Webpack 更易上手

最小配置
#

// rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";

export default {
  input: "src/index.js",
  output: {
    file: "dist/bundle.js",
    format: "es",
  },
  plugins: [resolve(), commonjs()],
};

推荐工作流
#

# 1. 安装依赖
pnpm add -D rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs

# 2. 创建配置文件 rollup.config.js

# 3. 配置 package.json
{
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w"
  },
  "main": "dist/index.cjs.js",
  "module": "dist/index.esm.js",
  "types": "dist/types/index.d.ts"
}

# 4. 打包
pnpm build

关键要点
#

  1. 正确配置 external:不打包运行时依赖和 peerDependencies
  2. 多格式输出:提供 ES + CJS + UMD 满足不同场景
  3. 生成类型声明:TypeScript 项目必需生成 .d.ts 文件
  4. 启用 Source Map:方便调试和错误追踪
  5. 使用合适的插件:根据项目需求选择必要插件
  6. 启用 Tree-shaking:充分利用 Rollup 的优势
  7. 配置 watch 模式:开发时提高效率
  8. 性能优化:使用缓存、并行处理

适用场景
#

推荐使用 Rollup

  • 打包 JavaScript/TypeScript 库
  • 打包 Vue/React 组件库
  • Monorepo 子包构建
  • 工具库和插件

不推荐使用 Rollup

  • 复杂的 Web 应用(推荐 Vite/Webpack)
  • 需要 HMR 开发服务器(推荐 Vite)
  • 大量静态资源处理

学习路径
#

  1. 基础(1-2 天)

    • 理解 ES modules
    • 掌握基础配置
    • 了解常用插件
  2. 实践(3-5 天)

    • 打包简单库
    • 配置多格式输出
    • 处理常见问题
  3. 进阶(1-2 周)

    • Tree-shaking 优化
    • 代码分割策略
    • 自定义插件开发
  4. 精通(持续学习)

    • 性能优化
    • 复杂场景处理
    • 与其他工具集成

参考资源
#


🎉 使用 Rollup,打包最干净、最优化的 JavaScript 库!

相关文章