Rollup 是一款基于 ES 模块(ESM)的 JavaScript 打包工具,专注于构建高性能、轻量的库或应用,尤其适合库的开发。
本文后续示例 rollup 版本4.59.0
rullop 核心特点
- 基于 ESM:原生支持 ES6 模块语法(
import/export),对模块依赖处理更高效。 - 强大的 Tree-shaking:静态分析代码,移除未被引用的 exports,减少打包体积(Webpack 也支持,但 Rollup 更早原生实现)。
- 简洁的输出:默认生成无冗余代码的 bundle,更接近手写代码,可读性高。
- 多输出格式:支持输出多种模块格式,如
es(ES 模块)、cjs(CommonJS)、umd(通用模块定义)、iife(立即执行函数)等,方便库在不同环境使用。 - 插件生态:通过插件扩展功能(如处理 CSS、图片、转换 TypeScript 等),但生态规模小于 Webpack。
Rollup 打包核心流程
Rollup 的打包过程可分为「初始化 → 构建 → 输出」三大模块,细分为 7 个核心阶段,整体流程如下:
rollup 基本配置
rollup-4.52.5/src/rollup/rollup.ts
function rollup(rawInputOptions: RollupOptions): Promise<RollupBuild> {
return rollupInternal(rawInputOptions, null);
}
interface RollupOptions extends InputOptions {
output?: OutputOptions | OutputOptions[] | undefined;
}
interface InputOptions {
cache?: boolean | RollupCache | undefined; // 启用打包缓存
context?: string | undefined; // 定义模块的 this 上下文
experimentalCacheExpiry?: number | undefined; // 缓存过期时间(秒)
experimentalLogSideEffects?: boolean | undefined; // 记录模块的副作用信息
external?: ExternalOption | undefined; // 标记「不打包」的依赖
fs?: RollupFsModule | undefined; // 自定义文件系统模块
input?: InputOption | undefined; // 指定打包入口文件
jsx?: false | JsxPreset | JsxOptions | undefined; // 内置 JSX 处理配置
logLevel?: LogLevelOption | undefined; // 控制日志输出级别
// 让绝对路径的外部依赖转为相对路径
makeAbsoluteExternalsRelative?: boolean | 'ifRelativeSource' | undefined;
// 限制并行文件操作数量
maxParallelFileOps?: number | undefined;
// 为特定模块自定义 this 上下文
moduleContext?: ((id: string) => string | NullValue) | Record<string, string> | undefined;
onLog?: LogHandlerWithDefault | undefined;
onwarn?: WarningHandlerWithDefault | undefined; // 自定义警告处理逻辑
perf?: boolean | undefined; // 输出性能分析数据
plugins?: InputPluginOption | undefined;
// 保留导出签名
preserveEntrySignatures?: PreserveEntrySignaturesOption | undefined;
preserveSymlinks?: boolean | undefined; // 保留符号链接(软链接)
// 为缺失的导出自动生成空垫片
shimMissingExports?: boolean | undefined;
strictDeprecations?: boolean | undefined; // 严格模式(弃用 API 直接报错)
// 控制 Tree-shaking 行为
treeshake?: boolean | TreeshakingPreset | TreeshakingOptions | undefined;
// 配置 watch 模式(热更新)
watch?: WatcherOptions | false | undefined;
}
input 配置
type InputOption = string | string[] | Record<string, string>;
external 配置
type ExternalOption =
| (string | RegExp)[]
| string
| RegExp
| ((source: string, importer: string | undefined, isResolved: boolean) => boolean | NullValue);
treeshake 配置
注意:Tree Shaking 仅对 ES 模块(
import/export)有效,CommonJS 模块(require)因动态特性无法被摇树。
treeshake?: boolean | TreeshakingPreset | TreeshakingOptions | undefined;
type TreeshakingPreset = 'smallest' | 'safest' | 'recommended';
- recommended,平衡体积和安全性,保留必要副作用
- smallest,极致摇树,尽可能剔除代码(可能误删副作用)
- safest,保守摇树,避免误删代码(体积稍大)
interface NormalizedTreeshakingOptions {
// 尊重代码中的 /*#__PURE__*/ 注释(标记无副作用的函数)
annotations: boolean;
// 是否修正「变量声明前使用」的逻辑
correctVarValueBeforeDeclaration: boolean;
// 手动标记的纯函数列表
manualPureFunctions: readonly string[];
// 控制模块级别的副作用判断
moduleSideEffects: HasModuleSideEffects;
// 属性读取是否有副作用
propertyReadSideEffects: boolean | 'always';
// try/catch 块是否禁用摇树(关闭可优化死代码剔除)
tryCatchDeoptimization: boolean;
// 全局变量操作是否有副作用
unknownGlobalSideEffects: boolean;
}
jsx 配置
jsx 配置项,是 Rollup v4.20+ 新增的实验性内置 JSX 处理能力。
- false, 禁用 Rollup 内置 JSX 处理(默认值,兼容历史行为)。
jsx?: false | JsxPreset | JsxOptions | undefined; // 内置 JSX 处理配置
- JsxPreset,使用内置预设快速配置,无需自定义参数
type JsxPreset = 'react' | 'react-jsx' | 'preserve' | 'preserve-react';
- JsxOptions,精细化配置 JSX 编译规则(优先级最高)
type JsxOptions = Partial<NormalizedJsxOptions> & {
preset?: JsxPreset | undefined;
};
interface NormalizedJsxAutomaticOptions {
// JSX 编译后的工厂函数
factory: string;
// JSX 运行时导入源(如 'react' / 'preact')
importSource: string | null;
// 最终生效的 JSX 运行时导入源
jsxImportSource: string;
// 固定值:标识当前 JSX 运行时模式
mode: 'automatic';
}
watch 配置
watch?: WatcherOptions | false | undefined;
interface WatcherOptions {
// 允许「输入文件(源码)」放在「输出目录(dist)」中
allowInputInsideOutputPath?: boolean | undefined;
// 文件变更后,延迟 N 毫秒再触发重新打包
buildDelay?: number | undefined;
// 传递给底层监听库 chokidar 的配置
chokidar?: ChokidarOptions | undefined;
// 重新打包时是否清空终端屏幕
clearScreen?: boolean | undefined;
// 排除不需要监听的文件 / 目录
exclude?: string | RegExp | (string | RegExp)[] | undefined;
// 指定需要监听的文件 / 目录
include?: string | RegExp | (string | RegExp)[] | undefined;
// 重新打包时是否跳过「写入文件到磁盘」
skipWrite?: boolean | undefined;
// 文件失效(变更 / 删除)时的回调函数
onInvalidate?: ((id: string) => void) | undefined;
}
interface ChokidarOptions {
// 是否每次触发事件时都调用 fs.stat() 获取文件信息
alwaysStat?: boolean | undefined;
// 处理「原子写入」的文件事件
atomic?: boolean | number | undefined;
// 等待文件「写入完成」后再触发事件
awaitWriteFinish?:
| {
pollInterval?: number | undefined; // 检查文件大小的间隔(ms),默认 100
stabilityThreshold?: number | undefined; // 文件大小稳定的时间(ms),默认 2000
}
| boolean
| undefined;
// 监听二进制文件的轮询间隔(ms)
binaryInterval?: number | undefined;
// 监听的工作目录(相对路径的基准)
cwd?: string | undefined;
// 监听目录的深度(递归层级)
depth?: number | undefined;
// 是否禁用 glob 路径解析
disableGlobbing?: boolean | undefined;
// 是否跟随符号链接
followSymlinks?: boolean | undefined;
// 是否忽略初始扫描
ignoreInitial?: boolean | undefined;
// 是否忽略文件权限错误
ignorePermissionErrors?: boolean | undefined;
// 忽略不需要监听的文件 / 目录
ignored?: any | undefined;
// 轮询间隔(ms),仅 usePolling: true 时生效
interval?: number | undefined;
// 监听进程是否持续运行(不退出)
persistent?: boolean | undefined;
// 是否使用 macOS 原生的 fsevents 模块
useFsEvents?: boolean | undefined;
// 是否使用轮询模式
usePolling?: boolean | undefined;
}
output 配置
interface OutputOptions {
amd?: AmdOptions | undefined; // 自定义 AMD 模块配置
// 静态资源(CSS / 图片等)的命名
assetFileNames?: string | ((chunkInfo: PreRenderedAsset) => string) | undefined;
banner?: string | AddonFunction | undefined; // 产物头部添加内容
// 动态导入 / 代码分割的 chunk 命名
chunkFileNames?: string | ((chunkInfo: PreRenderedChunk) => string) | undefined;
compact?: boolean | undefined; // 简单压缩代码
// only required for bundle.write
dir?: string | undefined; // 输出目录路径 (多文件输出)
// 在 CJS 输出中使用原生 import(),而非 Rollup 兼容封装
dynamicImportInCjs?: boolean | undefined;
// 入口 chunk 的文件名规则
entryFileNames?: string | ((chunkInfo: PreRenderedChunk) => string) | undefined;
esModule?: boolean | 'if-default-prop' | undefined; // 控制 ES 模块标记
// 实验性:避免生成过小的 chunk(优化网络请求)
experimentalMinChunkSize?: number | undefined; // 最小 chunk 大小
// 控制导出模式
exports?: 'default' | 'named' | 'none' | 'auto' | undefined;
extend?: boolean | undefined; // 扩展全局变量
/** @deprecated Use "externalImportAttributes" instead. */
externalImportAssertions?: boolean | undefined; // 导入断言(已废弃)
externalImportAttributes?: boolean | undefined; // 启用导入属性
// 是否为 external 依赖生成 “活绑定”,true 更符合 ESM 规范
externalLiveBindings?: boolean | undefined;
// only required for bundle.write
file?: string | undefined; // 输出文件路径
footer?: string | AddonFunction | undefined; // 产物尾部添加内容
format?: ModuleFormat | undefined; // 指定输出模块格式
freeze?: boolean | undefined; // 是否使用 Object.freeze 冻结导出对象(默认 true)
// 控制生成代码的版本:ES5、ES6、箭头函数等语法级别
generatedCode?: GeneratedCodePreset | GeneratedCodeOptions | undefined;
globals?: GlobalsOption | undefined; // UMD/CJS 中外部依赖的全局变量映射
hashCharacters?: HashCharacters | undefined; // 自定义 content hash 用的字符集
// 把间接依赖的 import 提升到顶层,减少嵌套、提升运行效率
hoistTransitiveImports?: boolean | undefined;
// 自定义导入属性 key,如 assert / with
importAttributesKey?: ImportAttributesKey | undefined;
indent?: string | boolean | undefined; // 缩进格式
// 把动态导入直接内联,不做代码分割
inlineDynamicImports?: boolean | undefined;
interop?: InteropType | GetInterop | undefined; // 模块互操作方式
intro?: string | AddonFunction | undefined; // 模块内部添加内容
manualChunks?: ManualChunksOption | undefined; // 自定义代码分割
// 压缩内部导出名称,缩短变量名
minifyInternalExports?: boolean | undefined;
name?: string | undefined; // UMD/iife 格式的全局变量名
noConflict?: boolean | undefined; // 添加 noConflict 方法
/** @deprecated This will be the new default in Rollup 5. */
// 弃用提示:Rollup 5 会成为默认值,禁用自动分割
onlyExplicitManualChunks?: boolean | undefined; // 仅使用显式手动分割
outro?: string | AddonFunction | undefined; // 模块尾部添加内容
paths?: OptionsPaths | undefined; // 自定义导入路径
plugins?: OutputPluginOption | undefined;
preserveModules?: boolean | undefined; // 保留原模块结构
preserveModulesRoot?: string | undefined; // 保留模块结构的根目录
// 是否从外部模块重新导出原型
reexportProtoFromExternal?: boolean | undefined;
// 清理非法文件名
sanitizeFileName?: boolean | ((fileName: string) => string) | undefined;
// 生成源码映射(Sourcemap)
sourcemap?: boolean | 'inline' | 'hidden' | undefined;
sourcemapBaseUrl?: string | undefined; // 源码映射的基础 URL
sourcemapExcludeSources?: boolean | undefined; // 排除源码内容
sourcemapFile?: string | undefined; // 指定 sourcemap 内部引用的源文件名
// 自定义生成的 .map 文件名
sourcemapFileNames?:
string | ((chunkInfo: PreRenderedChunk) => string) | undefined;
// 让浏览器 devtools 忽略某些 sourcemap
sourcemapIgnoreList?: boolean | SourcemapIgnoreListOption | undefined;
// 转换源码路径
sourcemapPathTransform?: SourcemapPathTransformOption | undefined;
sourcemapDebugIds?: boolean | undefined; // 给 sourcemap 添加稳定 debug ID
strict?: boolean | undefined; // 产物是否加 'use strict'(默认 true)
// SystemJS 格式:使用空 setter,优化加载
systemNullSetters?: boolean | undefined;
validate?: boolean | undefined; // 对最终打包代码做校验,防止语法错误
virtualDirname?: string | undefined; // 为虚拟模块设置 __dirname
}
format
type ModuleFormat = InternalModuleFormat | 'commonjs' | 'esm' | 'module' | 'systemjs';
type InternalModuleFormat = 'amd' | 'cjs' | 'es' | 'iife' | 'system' | 'umd';
manualChunks
manualChunks?: ManualChunksOption | undefined; // 自定义代码分割
// Record<string, string[]> 静态映射(chunk名 → 模块列表)
type ManualChunksOption = Record<string, string[]> | GetManualChunk;
// 动态函数(根据模块ID返回chunk名)
type GetManualChunk = (
id: string, // 当前模块的唯一ID(文件路径/模块名)
meta: ManualChunkMeta // 模块元信息(获取所有模块/模块详情)
) => string | NullValue;
interface ManualChunkMeta {
// 获取所有参与打包的模块ID
getModuleIds: () => IterableIterator<string>;
getModuleInfo: GetModuleInfo;
}
type GetModuleInfo = (moduleId: string) => ModuleInfo | null;
interface ModuleInfo extends ModuleOptions {
ast: ProgramNode | null; // 模块的抽象语法树(AST)
code: string | null; // 模块处理后的代码(插件转换后)
dynamicImporters: readonly string[]; // 动态导入当前模块的模块ID(import())
dynamicallyImportedIdResolutions: readonly ResolvedId[]; // 动态导入模块的解析详情
dynamicallyImportedIds: readonly string[]; // 当前模块动态导入的模块ID
exportedBindings: Record<string, string[]> | null; // 导出名对应的变量名(解决重命名)
exports: string[] | null; // 当前模块的所有导出名称
safeVariableNames: Record<string, string> | null; // 安全变量名(避免冲突)
hasDefaultExport: boolean | null; // 是否有默认导出
id: string; // 模块唯一ID(绝对路径/裸模块名)
implicitlyLoadedAfterOneOf: readonly string[]; // 隐式加载依赖(高级)
implicitlyLoadedBefore: readonly string[]; // 隐式被依赖(高级)
importedIdResolutions: readonly ResolvedId[]; // 导入模块的解析详情(路径/是否外部)
importedIds: readonly string[]; // 当前模块导入的所有模块ID
importers: readonly string[]; // 引用当前模块的所有模块ID(反向依赖)
isEntry: boolean; // 是否是入口模块
isExternal: boolean; // 是否是外部依赖(如external配置的模块)
isIncluded: boolean | null; // 是否被包含在最终产物中
}
interface ModuleOptions {
// 模块属性
attributes: Record<string, string>;
// 插件自定义元数据(插件间共享数据)
meta: CustomPluginOptions;
// 模块级副作用控制(Tree Shaking 核心)
moduleSideEffects: boolean | 'no-treeshake';
// 合成命名导出(兼容 CommonJS/默认导出)
syntheticNamedExports: boolean | string;
}
hashCharacters
hashCharacters?: HashCharacters | undefined; // 自定义 content hash 用的字符集
type HashCharacters = 'base64' | 'base36' | 'hex';
base64,字符集(A-Z、a-z、0-9、+、/) 最短(6 位≈hex 8 位)base36,字符集(0-9、a-z(小写字母)) 中等(7 位≈hex 8 位)hex,字符集(0-9、a-f(小写十六进制)) 最长(8 位)
plugins 配置
type InputPluginOption =
MaybePromise< // 支持同步/异步插件(Promise 包裹)
Plugin | // 单个合法插件实例(核心)
NullValue | // null/undefined(无插件)
false | // false(禁用该插件)
InputPluginOption[] // 嵌套数组(支持多层插件列表)
>;
应用
第一步: 安装 rollup 依赖
# 安装
npm install rollup --save-dev
第二步 配置文件 rollup.config.js(ts、cjs、mjs)
执行命令
rollup -c
其他
- 官网:rollupjs.org/
- rollup 配置: rollupjs.org/configurati…