Rollup 打包学习 - 实战笔记

Rollup 更适合做工具库、组件库的产物构建,适合追求输出精简,格式多样,可控性强的前端开发需求。

但是对于想做Web应用开发的,则不是很合适,Vite、Webpack、Rsbuild或许是更好的选择

一、常见打包格式

1.1 IIFE (Immediately Invoked Function Expression) 立即执行函数表达式

IIFE是最适合直接在浏览器<script>标签引用的格式,也是曾经被广泛使用的格式

整个代码被包在一个自调用函数里,从而保证不向全局变量泄露内部变量,导致全局变量被污染

javascript
(function () {
  const msg = "Hello IIFE";
  console.log(msg);
})();

1.2 ESM (ES Modules 模块)

ESM是现代JavaScript 官方模块,在没有ESM的时代,JavaScript 主要靠 CommonJS (Node) + Browserify/Webpack 和 AMD (RequireJS)来实现模块化和打包

ESM 支持静态分析、tree-shaking,是目前主流的打包格式

javascript
// math.js
export const add = (a, b) => a + b;

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

浏览器原生支持:

html
<script type="module">
  import { add } from './math.js';
  console.log(add(2, 3));
</script>

1.3 CJS (CommonJS) Node.js 的经典模块格式

在还没有ESM的时候,Node.js 自己实现的一种模块格式,他是一种同步导入模块的方式

你甚至可以直接从 node_modules 中引入一个库或者文本目录引入一个文件,都是支持的比如:const myLocalModule = require('./some/local/file.js') 或者是 var React = require('react'); 都是有效的写法

这种格式不支持直接在浏览器中运行

javascript
// importing 
const doSomething = require('./doSomething.js'); 

// exporting
module.exports = function doSomething(n) {
  // do something
}

require 动态加载无法静态分析 → 无法 tree-shaking

1.4 UMD (Universal Module Definition) 通用格式

UMD 兼容 IIFE + CJS + AMD 模块系统

设计出来就是想一个文件可以在各种环境运行 - 浏览器、Node、RequireJS 都可以通用

javascript
(function (root, factory) {
    if (typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();                  // Node (CJS)
    else if (typeof define === 'function' && define.amd)
        define([], factory);                         // AMD
    else
        root.MyLib = factory();                      // 浏览器全局
})(this, function () {
    return {
        add(a, b) { return a + b; }
    };
});

浏览器用:

html
<script src="mylib.umd.js"></script>
<script>
  console.log(MyLib.add(1, 2));
</script>

Node 用:

javascript
const MyLib = require('./mylib.umd.js');
特性说明
✅ 通用性最强,浏览器+Node 都能直接用
✅ 适合发 npm 包兼容老生态
❌ 文件较大,结构复杂
❌ 不具备 ESM 的 tree-shaking 优势

二、简单例子,上手rollup基础配置

从一个简单的例子开始上手

2.1 安装

初始化一个项目以后,在项目中安装包

bash
npm install -D rollup

2.2 配置、代码

一个最基础的配置,同时打包出 esm、cjs、umd

rollup.config.js
export default {
  input: 'src/index.js',
  output: [
    { file: 'dist/index.esm.js', format: 'esm' },
    { file: 'dist/index.cjs.js', format: 'cjs' },
    { file: 'dist/index.umd.js', format: 'umd', name: 'MyLib' },
  ]
}

写一个简单的例子:

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

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

配置一下package.json 增加一个build参数

json
{
  "name": "rollup-pack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "rollup -c rollup.config.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "rollup": "^4.52.5"
  }
}

打包命令:

bash
npm run build

输出打包后的单文件,浏览器、Node 都能直接用,打包产物如下

三、如何引入TypeScript ?

3.1 新建项目与安装

bash
# 1) 新建目录与初始化
mkdir my-lib && cd my-lib
npm init -y

# 2) 安装 rollup 与常用插件
npm i -D rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-json

# 3) 压缩与环境变量替换(可选)
npm i -D @rollup/plugin-terser @rollup/plugin-replace

# 4) TypeScript 支持(后文用到)
npm i -D typescript @rollup/plugin-typescript rollup-plugin-dts

# 5) 类型检查/声明生成(可选但强烈建议)
npx tsc --init

目录建议:

text
my-lib/
  ├─ src/
  │   └─ index.ts        # 入口(JS 项目可用 .js)
  ├─ rollup.config.mjs   # Rollup 配置(ESM)
  ├─ package.json
  └─ tsconfig.json

3.2 基础配置

tsconfig.json 配置,支持TypeScript

json

{
    "compilerOptions": {
        "module": "ESNext", // 让 TS 仅做类型检查与转译协作
        "target": "ES2020",
        "types": [],
        "sourceMap": true,
        "moduleResolution": "Bundler", // 与 Rollup 更匹配(或 "NodeNext")
        "declaration": true, // 生成 .d.ts
        "declarationMap": true,
        "emitDeclarationOnly": false, // 由 Rollup 统一产物(dts 另见下节)
        "noUncheckedIndexedAccess": true,
        "exactOptionalPropertyTypes": true,
        "strict": true,
        "jsx": "react-jsx",
        "verbatimModuleSyntax": true,
        "isolatedModules": true,
        "noUncheckedSideEffectImports": true,
        "moduleDetection": "force",
        "skipLibCheck": true,
        "paths": {
            "@/*": [
                "./src/*"
            ]
        }
    },
    "baseUrl": ".",
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "node_modules",
        "dist"
    ]
}

源码:src/index.ts

javascript
import { add } from '@/add';
console.log(add(1, 2));

源代码:src/add.ts

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

还需要配置一下rollup来支持typeScript

javascript
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import replace from '@rollup/plugin-replace';
import terser from '@rollup/plugin-terser';
import typescript from '@rollup/plugin-typescript';
import dts from 'rollup-plugin-dts';

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

// 主构建(js)
const main = {
    input: 'src/index.ts',
    external: [], // 如 ['react']
    plugins: [
        resolve({ extensions: ['.mjs', '.js', '.json', '.ts'] }),
        commonjs(),
        json(),
        replace({
            preventAssignment: true,
            'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
        }),
        typescript({
            tsconfig: './tsconfig.json',
            declaration: false,     // 由 dts 插件单独处理
            outDir: undefined
        }),
        isProd && terser(),
    ],
    output: [
        { file: 'dist/index.esm.js', format: 'esm', sourcemap: true },
        { file: 'dist/index.cjs.js', format: 'cjs', sourcemap: true },
        { file: 'dist/index.umd.js', format: 'umd', name: 'MyLib', sourcemap: true }
    ]
};

// 类型声明打包(.d.ts)
const types = {
    input: 'dist/types/src/index.d.ts', // 由 tsc 先产出到 dist/types
    output: [{ file: 'dist/index.d.ts', format: 'es' }],
    plugins: [dts()],
};

// 默认导出数组可以同时执行多任务构建
export default [main, types];

这个配置主要做两件事

  1. 把TS源代码变异成JS产物,分别输出 ESM、CJS、UMD
  2. 把 TypeScript .d.ts 类型声明拆开产出的碎文件合并成一个
    • 最终得到 dist/index.d.ts

external 参数作用

javascript
external: ['react', 'react-dom']

指定哪些依赖不打入产物。例如如果你的库依赖 React,填进去以后就不会将react打包进bundle,这样做,打包出来的体积会更小

plugin 说明

javascript
  plugins: [
    resolve({ extensions: ['.mjs', '.js', '.json', '.ts'] }),
    commonjs(),
    json(),
    replace({
      preventAssignment: true,
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
    }),
    typescript({
      tsconfig: './tsconfig.json',
      declaration: false,     // 由 dts 插件单独处理
      outDir: undefined
    }),
    isProd && terser(),
  ]
  • resolve: 识别 node 模块、拓展名
  • commonjs: 转换 CommonJS 模块
  • json:支持JSON导入
  • typescript: 处理typescript文件


了解 Hana - 探索有趣的世界 的更多信息

订阅后即可通过电子邮件收到最新文章。

相关推荐

暂无评论

发表评论

您的电子邮件地址不会被公开,必填项已用*标注。