Skip to content

Rollup 介绍

什么是 Rollup

Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。Rollup 对代码模块使用 ES Module 标准,而不是之前的特殊解决方案(如 CommonJS 和 AMD)。

Rollup 的核心特点

ES Module 优先

  • 原生支持 ES Module
  • 静态分析能力
  • 更高效的 Tree Shaking

Tree Shaking

  • 自动移除未使用的代码
  • 基于静态分析
  • 生成更小的包

输出格式多样

  • 支持多种输出格式
  • IIFE、AMD、CJS、UMD、ESM
  • 适合不同使用场景

配置简洁

  • 配置文件简单
  • API 清晰
  • 易于理解和使用

Rollup 的工作原理

构建流程

入口文件

解析 AST

分析依赖关系

构建依赖图

Tree Shaking

代码生成

输出文件

静态分析

Rollup 利用 ES Module 的静态特性:

javascript
// 静态导入 - 编译时确定
import { foo } from './module';

// 动态导入 - 运行时确定(Rollup 也支持)
const module = await import('./module');

Tree Shaking 原理

javascript
// utils.js
export function used() {
  console.log('used');
}

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

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

// 打包后 - unused 函数被移除
function used() {
  console.log('used');
}
used();

作用域提升

Rollup 将所有模块合并到一个函数作用域中:

javascript
// 打包前
// moduleA.js
export const a = 1;

// moduleB.js
export const b = 2;

// main.js
import { a } from './moduleA';
import { b } from './moduleB';
console.log(a, b);

// 打包后
(function() {
  const a = 1;
  const b = 2;
  console.log(a, b);
})();

Rollup 的配置

基础配置

javascript
export default {
  input: 'src/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'esm'
  }
};

多格式输出

javascript
export default {
  input: 'src/index.js',
  output: [
    {
      file: 'dist/bundle.cjs.js',
      format: 'cjs'
    },
    {
      file: 'dist/bundle.esm.js',
      format: 'esm'
    },
    {
      file: 'dist/bundle.umd.js',
      format: 'umd',
      name: 'MyLibrary'
    }
  ]
};

使用插件

javascript
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/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'esm'
  },
  plugins: [
    resolve(),
    commonjs(),
    babel({ babelHelpers: 'bundled' }),
    terser()
  ]
};

代码分割

javascript
export default {
  input: ['src/index.js', 'src/secondary.js'],
  output: {
    dir: 'dist',
    format: 'esm'
  }
};

动态导入

javascript
export default {
  input: 'src/index.js',
  output: {
    dir: 'dist',
    format: 'esm',
    chunkFileNames: 'chunks/[name]-[hash].js'
  }
};

输出格式详解

ES Module (esm)

javascript
// 输出格式
export const foo = 'bar';
export function baz() {}

CommonJS (cjs)

javascript
// 输出格式
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const foo = 'bar';
exports.foo = foo;

UMD (Universal Module Definition)

javascript
// 输出格式
(function(global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MyLibrary = {}));
}(this, (function(exports) {
  'use strict';
  const foo = 'bar';
  exports.foo = foo;
})));

IIFE (Immediately Invoked Function Expression)

javascript
// 输出格式
var MyLibrary = (function() {
  'use strict';
  const foo = 'bar';
  return { foo: foo };
})();

AMD

javascript
// 输出格式
define(['exports'], function(exports) {
  'use strict';
  const foo = 'bar';
  exports.foo = foo;
});

Rollup 的优点

高效的 Tree Shaking

  • 基于静态分析
  • 自动移除死代码
  • 更小的输出体积

干净的输出

  • 代码可读性高
  • 没有额外的运行时代码
  • 适合库开发

多格式支持

  • 支持所有主流模块格式
  • 一次配置多格式输出
  • 灵活的使用场景

配置简单

  • 配置文件简洁
  • 概念清晰
  • 学习成本低

插件机制

  • 灵活的插件系统
  • 丰富的插件生态
  • 易于扩展

Rollup 的缺点

功能相对简单

  • 不如 Webpack 功能全面
  • 缺少一些开发时功能
  • 需要插件支持更多功能

开发体验

  • 没有内置开发服务器
  • HMR 需要额外配置
  • 不适合复杂应用开发

资源处理

  • 需要插件处理 CSS、图片等
  • 不如 Webpack 方便
  • 配置相对繁琐

生态规模

  • 插件数量少于 Webpack
  • 社区相对较小
  • 某些功能支持不完善

常用插件

官方插件

插件用途
@rollup/plugin-node-resolve解析 node_modules 中的模块
@rollup/plugin-commonjs转换 CommonJS 模块
@rollup/plugin-babelBabel 编译
@rollup/plugin-json导入 JSON 文件
@rollup/plugin-url导入文件为 URL
@rollup/plugin-virtual虚拟模块

社区插件

插件用途
rollup-plugin-terser代码压缩
rollup-plugin-typescript2TypeScript 支持
rollup-plugin-postcssCSS 处理
rollup-plugin-livereload热重载
rollup-plugin-serve开发服务器
rollup-plugin-filesize显示文件大小

插件开发

插件结构

javascript
export default function myPlugin(options = {}) {
  return {
    name: 'my-plugin',
    
    buildStart(options) {
      console.log('构建开始');
    },
    
    resolveId(source, importer) {
      if (source === 'virtual-module') {
        return source;
      }
      return null;
    },
    
    load(id) {
      if (id === 'virtual-module') {
        return 'export default "This is virtual"';
      }
      return null;
    },
    
    transform(code, id) {
      if (id.endsWith('.custom')) {
        return {
          code: `export default ${JSON.stringify(code)}`,
          map: { mappings: '' }
        };
      }
      return null;
    },
    
    buildEnd(error) {
      if (error) {
        console.error('构建错误:', error);
      }
    }
  };
}

插件钩子

钩子类型用途
options同步修改配置
buildStart异步构建开始
resolveId同步/异步解析模块 ID
load同步/异步加载模块
transform同步/异步转换代码
buildEnd异步构建结束
renderStart异步生成阶段开始
renderChunk同步/异步处理每个 chunk
generateBundle异步生成完成
writeBundle异步写入完成

高级配置

外部依赖

javascript
export default {
  input: 'src/index.js',
  external: ['react', 'react-dom', 'lodash'],
  output: {
    globals: {
      react: 'React',
      'react-dom': 'ReactDOM',
      lodash: '_'
    }
  }
};

条件导出

javascript
export default {
  input: 'src/index.js',
  output: {
    exports: 'named' // 'auto' | 'default' | 'named' | 'none'
  }
};

Source Map

javascript
export default {
  input: 'src/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'esm',
    sourcemap: true,
    sourcemapFile: 'dist/bundle.js.map'
  }
};

保留模块结构

javascript
export default {
  input: 'src/index.js',
  preserveModules: true,
  output: {
    dir: 'dist',
    format: 'esm'
  }
};

Rollup 的应用场景

库开发

  • npm 包开发
  • UI 组件库
  • 工具函数库
  • 插件开发

简单应用

  • 小型 Web 应用
  • 静态网站
  • 简单单页应用

Vite 生产构建

  • Vite 底层使用 Rollup
  • 生产环境打包

命令行工具

bash
# 基本使用
rollup src/index.js --file dist/bundle.js --format esm

# 使用配置文件
rollup -c

# 指定配置文件
rollup -c rollup.config.js

# 监听模式
rollup -c -w

# 指定输入输出
rollup src/index.js -o dist/bundle.js -f cjs

# 生成 source map
rollup src/index.js -o dist/bundle.js -f esm -m

与 Webpack 的对比

特性RollupWebpack
Tree Shaking原生支持,效果好支持,效果稍差
输出代码干净、可读有运行时代码
配置复杂度简单复杂
开发服务器需要插件内置
HMR需要插件内置
代码分割支持强大
适用场景库开发应用开发
生态较小庞大

最佳实践

库开发配置

javascript
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from 'rollup-plugin-typescript2';
import { terser } from 'rollup-plugin-terser';

const pkg = require('./package.json');

export default [
  {
    input: 'src/index.ts',
    output: [
      { file: pkg.main, format: 'cjs' },
      { file: pkg.module, format: 'esm' }
    ],
    external: [...Object.keys(pkg.dependencies || {})],
    plugins: [
      resolve(),
      commonjs(),
      typescript(),
      terser()
    ]
  }
];

开发环境配置

javascript
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import serve from 'rollup-plugin-serve';

export default {
  input: 'src/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'iife',
    sourcemap: true
  },
  plugins: [
    resolve(),
    commonjs(),
    serve({
      contentBase: 'dist',
      port: 3000
    }),
    livereload()
  ]
};

基于 VitePress 的本地知识库