aurora blog
  • JS

    • 基本汇总
    • Date时间
    • Array方法
    • String 方法
    • Object方法
    • RegExp正则
    • Es6 新特性等
    • Event-Loop
    • Http and Https
    • for in和for of区别
    • Web Worker
    • Promise && async
    • 堆内存 & 栈内存
    • JS设计模式探索
    • npm & yarn
    • Fetch和Axios的区别
    • 学习及面试问题整理
    • URL 输入到页面加载过程
    • 跨域&nginx本地项目代理
  • FE框架

    • react

      • 基本用法
      • react生命周期
      • hooks 16.8版本后
      • Route原理
      • Redux源码解析
      • React16 Fiber
      • React-VirtualDOM
      • React事件委托机制
      • React性能优化
      • 状态管理方案对比
      • React 18新特性
    • vue

      • vue 基本用法
      • vue 生命周期
      • VirtualDOM
      • vue 事件委托
      • vue 架构
      • vue 状态管理
      • 问题等
    • React-Native

      • React-Native 基本用法
    • 微前端

      • 遇到的问题
    • 鸿蒙 harmony

      • harmony 基础
  • 构建工具

    • webpack

      • Webpack配置详解
      • Webpack的使用
      • Babel-polyfill
      • webpack面试题
    • vite

      • vite配置详解
      • vite面试题
    • rollup

      • Rollup配置详解
      • rollup面试题
    • 构建工具对比
  • 性能优化

    • 性能优化策略
    • 缓存策略
    • 性能优化面试题
  • 浏览器

    • 浏览器渲染原理
    • 浏览器缓存机制
    • 浏览器面试题
  • 工程化

    • 代码规范
    • 工程化面试题
  • 前端安全

    • XSS 攻击与防护
    • CSRF 攻击与防护
    • 前端安全面试题
  • 移动端开发

    • 移动端适配
    • 移动端开发面试题
  • 前端监控

    • 错误监控
    • 性能监控
    • 前端监控面试题
  • Typescript

    • Typescript详解
  • Servers

    • Nodejs
    • Nginx
  • Git命令

    • git常用规范
  • 数据库

    • mongodb
    • mongodb
  • Other

    • Jenkins自动化部署

Rollup 配置详解

  • 什么是 Rollup
  • 核心概念
    • 输入和输出
    • 输出格式
  • 基础配置
  • 常用插件
    • 核心插件
    • 编译插件
    • CSS 处理
    • 其他常用插件
  • 多入口配置
  • 代码分割
  • Tree Shaking
  • 外部依赖
  • 环境变量
  • 开发配置
  • 生产配置
  • 条件配置
  • 库开发配置示例
  • 性能优化
    • 1. 使用 esbuild 替代 Babel
    • 2. 并行构建
    • 3. 缓存
  • 常见问题
    • 1. CommonJS 模块无法解析
    • 2. Node.js 内置模块报错
    • 3. 动态导入问题
    • 4. 循环依赖
  • 与 Webpack 的区别
  • 最佳实践

什么是 Rollup

Rollup 是一个 JavaScript 模块打包器,专注于将小块代码编译成更大、更复杂的代码库。主要特点:

  • Tree Shaking:自动移除未使用的代码
  • ES Modules 优先:原生支持 ES modules
  • 输出格式多样:支持 ES、CommonJS、UMD、IIFE 等格式
  • 适合库开发:生成更小、更高效的代码

核心概念

输入和输出

// rollup.config.js
export default {
  input: 'src/main.js', // 入口文件
  output: {
    file: 'dist/bundle.js', // 输出文件
    format: 'es', // 输出格式
  },
};

输出格式

  • es:ES modules 格式
  • cjs:CommonJS 格式
  • umd:通用模块定义,支持 AMD、CommonJS 和全局变量
  • iife:立即执行函数表达式
  • amd:AMD 格式
  • system:SystemJS 格式

基础配置

// 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 { nodeResolve } from '@rollup/plugin-node-resolve';

export default {
  input: 'src/index.js',
  output: [
    {
      file: 'dist/bundle.esm.js',
      format: 'es',
      sourcemap: true,
    },
    {
      file: 'dist/bundle.cjs.js',
      format: 'cjs',
      sourcemap: true,
    },
    {
      file: 'dist/bundle.umd.js',
      format: 'umd',
      name: 'MyLibrary',
      sourcemap: true,
    },
  ],
  plugins: [
    resolve({
      browser: true,
      preferBuiltins: false,
    }),
    commonjs(),
    babel({
      babelHelpers: 'bundled',
      exclude: 'node_modules/**',
    }),
    terser(),
  ],
  external: ['react', 'react-dom'], // 外部依赖,不打包
};

常用插件

核心插件

import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import { nodeResolve } from '@rollup/plugin-node-resolve';

export default {
  plugins: [
    // 解析 node_modules 中的模块
    resolve({
      browser: true, // 浏览器环境
      preferBuiltins: false, // 不使用 Node.js 内置模块
      dedupe: ['vue'], // 去重
    }),
    
    // 将 CommonJS 转换为 ES modules
    commonjs({
      include: /node_modules/,
      transformMixedEsModules: true,
    }),
    
    // 导入 JSON 文件
    json(),
  ],
};

编译插件

import babel from '@rollup/plugin-babel';
import typescript from '@rollup/plugin-typescript';
import { esbuild } from 'rollup-plugin-esbuild';

export default {
  plugins: [
    // Babel 转换
    babel({
      babelHelpers: 'bundled', // 'bundled' | 'runtime' | 'inline' | 'external'
      exclude: 'node_modules/**',
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
    }),
    
    // TypeScript 支持
    typescript({
      tsconfig: './tsconfig.json',
      declaration: true,
      declarationDir: './dist/types',
    }),
    
    // esbuild(更快)
    esbuild({
      target: 'es2015',
      minify: process.env.NODE_ENV === 'production',
    }),
  ],
};

CSS 处理

import postcss from 'rollup-plugin-postcss';
import { visualizer } from 'rollup-plugin-visualizer';

export default {
  plugins: [
    postcss({
      extract: true, // 提取 CSS 到单独文件
      minimize: true, // 压缩 CSS
      sourceMap: true,
      plugins: [
        require('autoprefixer'),
        require('cssnano'),
      ],
    }),
  ],
};

其他常用插件

import replace from '@rollup/plugin-replace';
import alias from '@rollup/plugin-alias';
import { terser } from 'rollup-plugin-terser';
import { visualizer } from 'rollup-plugin-visualizer';
import filesize from 'rollup-plugin-filesize';

export default {
  plugins: [
    // 替换代码中的变量
    replace({
      'process.env.NODE_ENV': JSON.stringify('production'),
      __VERSION__: JSON.stringify(require('./package.json').version),
    }),
    
    // 路径别名
    alias({
      entries: [
        { find: '@', replacement: path.resolve(__dirname, 'src') },
      ],
    }),
    
    // 代码压缩
    terser({
      compress: {
        drop_console: true,
        drop_debugger: true,
      },
    }),
    
    // 打包分析
    visualizer({
      open: true,
      gzipSize: true,
    }),
    
    // 显示文件大小
    filesize(),
  ],
};

多入口配置

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

代码分割

export default {
  input: 'src/index.js',
  output: {
    dir: 'dist',
    format: 'es',
    manualChunks: {
      // 将 vendor 代码分离
      vendor: ['react', 'react-dom'],
      utils: ['./src/utils/helper1', './src/utils/helper2'],
    },
  },
};

Tree Shaking

Rollup 默认启用 Tree Shaking,但需要注意:

// ✅ 会被 Tree Shaking
export const used = () => {};
export const unused = () => {};

// ❌ 不会被 Tree Shaking(副作用)
export default {
  used: () => {},
  unused: () => {},
};

// ✅ 标记副作用
export default {
  used: () => {},
  unused: () => {},
  /*#__PURE__*/ someSideEffect(),
};

外部依赖

export default {
  external: [
    'react',
    'react-dom',
    /^lodash/, // 正则匹配
    (id) => id.includes('node_modules'), // 函数匹配
  ],
  output: {
    globals: {
      react: 'React',
      'react-dom': 'ReactDOM',
    },
  },
};

环境变量

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

export default {
  plugins: [
    replace({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
      'process.env.API_URL': JSON.stringify(process.env.API_URL || 'http://localhost:3000'),
    }),
  ],
};

开发配置

// rollup.config.dev.js
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';

export default {
  plugins: [
    serve({
      open: true,
      contentBase: 'dist',
      port: 3000,
    }),
    livereload('dist'),
  ],
};

生产配置

// rollup.config.prod.js
import { terser } from 'rollup-plugin-terser';
import { visualizer } from 'rollup-plugin-visualizer';

export default {
  plugins: [
    terser({
      compress: {
        drop_console: true,
        drop_debugger: true,
        pure_funcs: ['console.log'],
      },
    }),
    visualizer({
      filename: 'dist/stats.html',
    }),
  ],
};

条件配置

const isProduction = process.env.NODE_ENV === 'production';

export default {
  plugins: [
    ...(isProduction ? [terser()] : []),
  ],
  output: {
    sourcemap: !isProduction,
  },
};

库开发配置示例

// 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';

const name = 'MyLibrary';

export default {
  input: 'src/index.ts',
  output: [
    {
      file: pkg.main,
      format: 'cjs',
      sourcemap: true,
    },
    {
      file: pkg.module,
      format: 'es',
      sourcemap: true,
    },
    {
      file: pkg.browser,
      format: 'umd',
      name,
      sourcemap: true,
    },
  ],
  plugins: [
    resolve(),
    commonjs(),
    typescript({
      declaration: true,
      declarationDir: './dist/types',
    }),
    terser(),
  ],
  external: [
    ...Object.keys(pkg.dependencies || {}),
    ...Object.keys(pkg.peerDependencies || {}),
  ],
};

性能优化

1. 使用 esbuild 替代 Babel

import { esbuild } from 'rollup-plugin-esbuild';

// 比 Babel 快 10-100 倍
export default {
  plugins: [
    esbuild({
      target: 'es2015',
      minify: true,
    }),
  ],
};

2. 并行构建

import { rollup } from 'rollup';

const builds = [
  { format: 'es' },
  { format: 'cjs' },
  { format: 'umd' },
];

await Promise.all(
  builds.map(async (config) => {
    const bundle = await rollup(inputOptions);
    await bundle.write({ ...outputOptions, ...config });
  })
);

3. 缓存

import { rollup } from 'rollup';

let cache;

export default {
  cache,
  plugins: [...],
};

// 保存缓存
const { output, cache: newCache } = await bundle.generate(outputOptions);
cache = newCache;

常见问题

1. CommonJS 模块无法解析

使用 @rollup/plugin-commonjs 插件。

2. Node.js 内置模块报错

在 resolve 插件中设置 preferBuiltins: false。

3. 动态导入问题

使用 @rollup/plugin-dynamic-import-vars 处理动态导入。

4. 循环依赖

Rollup 会自动处理循环依赖,但建议重构代码避免。

与 Webpack 的区别

特性RollupWebpack
Tree Shaking默认启用,效果更好需要配置
代码体积更小较大
开发体验需要插件支持 HMR内置 HMR
适用场景库开发应用开发
配置复杂度简单复杂
插件生态较小丰富

最佳实践

  1. 库开发优先使用 Rollup:生成更小、更高效的代码
  2. 使用 ES modules:充分利用 Tree Shaking
  3. 合理使用 external:避免打包大型依赖
  4. 多格式输出:同时输出 ES、CommonJS、UMD 格式
  5. 类型声明:使用 TypeScript 插件生成类型声明文件
最近更新:: 2025/11/20 14:50
Contributors: liyulai
Next
rollup面试题