美文网首页
使用 Rollup 开发组件:打包基础

使用 Rollup 开发组件:打包基础

作者: RJ_Hwang | 来源:发表于2020-02-06 18:05 被阅读0次

Rollup 英文官网地址为 https://rollupjs.org。国内有个 Rollup 中文网,网址为 https://www.rollupjs.com

Rollup 是一个 JavaScript 模块打包器,可以将多个小型的模块混合编译成一个大模块,如库或应用程序。

我们直接使用新的 JavaScript 标准语法(如 ES6)来编写各种模块组件,这些模块组件之间会有相应的依赖关系,如模块 A 依赖模块 B 时,可能只使用了模块 B 中特定的函数功能,将模块 A、B 一起打包在一起时,模块 B 中没有使用的函数功能就会显得多余并且额外增加了混合打包后的组件大小。而使用 Rollup 进行打包的话,其自带的 Tree-Shaking 特征会使打包后的组件仅包含模块 B 中用到的功能,可以大大减少打包后组件的大小。

使用如下命令在全局范围内安装 Rollup,使可直接在命令行执行 rollup 命令:

$ npm install --global rollup
/path-to-node/bin/rollup -> /path-to-node/lib/node_modules/rollup/dist/bin/rollup
+ rollup@1.31.0
added 4 packages from 45 contributors in 3.738s
$ rollup -v
rollup v1.31.0

1. Rollup 打包的 Tree-Shaking 效果演示

下面以一个例子来说明使用 RollupTree-Shaking 打包的好处。

模块名称 依赖
m1 -
m2 m1

源码目录结构:

workspaces/
|--package.json
|--m1
|  |--package.json
|  |--index.js
|--m2
|  |--package.json
|  |--index.js
|  |--rollup.config.js

workspaces/package.json: (使用了 Yarn workspace 来简化多模块的配置)

{
  "private"   : true,
  "workspaces": ["m1", "m2"],
  "scripts"   : {
    "build": "yarn workspace m2 build && yarn workspace m2 build-c"
  }
}

m1/package.json: (无其它依赖)

{
  "name"   : "m1",
  "version": "0.1.0",
  "type"   : "module",
  "main"   : "index.js"
}

m1/index.js:(仅定义了两个公共函数 f1、f2)

const f1 = () => "m1f1";
const f2 = () => "m1f2";
export { f1, f2 };

m2/package.json:

{
  "name"           : "m2",
  "version"        : "0.1.0",
  "type"           : "module",
  "main"           : "index.js",
  "dependencies"   : {
    "m1": "0.1.0"
  },
  "devDependencies": {
    "@rollup/plugin-node-resolve": "^7.1.1"
  },
  "scripts"        : {
    // 将 m1 视作外部依赖模块打包
    "build": "rollup index.js --file dist/bundle.js --format esm --external m1",
    // 将 m1 模块源码混合进 m2 打包
    "build-c": "rollup -c"
  }
}

m2/index.js:(依赖 m1 的函数 f1)

import { f1 } from "m1";
const f = () => "m2f>" + f1();
export { f };

m2/rollup.config.js: (rollup 配置文件)

import resolve from "@rollup/plugin-node-resolve";
export default {
  input: "index.js",
  output: {
    file: "dist/bundle+m1.js",
    format: "esm"
  },
  plugins: [
    // https://github.com/rollup/plugins/tree/master/packages/node-resolve
    resolve({
      // 检查要 resolve 的模块必须是 ES2015 modules
      modulesOnly: true,
      // 只 resolve 指定的模块,其余的保留为 external 依赖
      resolveOnly: ["m1"]
    })
  ]
};

workspaces 目录下执行 yarn build 以两种方式分别使用 Rollup 打包 m2 模块:

$ yarn build
yarn run v1.21.1
$ yarn workspace m2 build && yarn workspace m2 build-c
$ rollup index.js --file dist/bundle.js --format esm --external m1

index.js → dist/bundle.js...
created dist/bundle.js in 77ms
$ rollup -c

index.js → dist/bundle+m1.js...
created dist/bundle+m1.js in 49ms
✨  Done in 2.83s.

打包完成后将产生两个打包后的文件:

  1. m2/dist/bundle.js - 将 m1 视作外部依赖模块打包
    import { f1 } from 'm1';
    const f = () => "m2f>" + f1();
    export { f };
    
  2. m2/dist/bundle+m1.js - 将 m1 模块源码混合进 m2 打包
    const f1 = () => "m1f1";
    const f = () => "m2f>" + f1();
    export { f };
    

对比这两个文件,可以看到第 2 种方式打包后的文件移除了对 m1 的依赖配置,直接将 m1 模块的函数 f1 源码打包进去了,m1 模块的函数 f2 由于没有使用则直接被丢弃。这就是 RollupTree-Shaking 效果。

相关源代码在这里

2. 补充说明

上述打包方式 1 中(yarn workspace m2 build),显式通过命令参数 --external m1 指定 m1 为外部依赖,这个参数是可选的,没有提供的话,Rollup 默认也会视作外部依赖处理,但是打包时会有相应的警告提示:

$ yarn workspace m2 build
yarn workspace v1.21.1
yarn run v1.21.1
$ rollup index.js --file dist/bundle.js --format esm

index.js → dist/bundle.js...
(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
m1 (imported by index.js)
created dist/bundle.js in 75ms
✨  Done in 0.40s.
✨  Done in 1.15s.

出现警告的原因是 m1 是一个外部依赖,而 Rollup 打包时默认只会将使用相对路径 import 的模块一起打包(如 import utils from "./utils.js"),其它的模块依赖将作为外部依赖(如上面的 import { f1 } from "m1")。详见官方文档《Warning: "Treating [module] as external dependency"》的说明。

上述打包方式 2 中(yarn workspace m2 build-c),将外部依赖的模块 m1 也一起打包,是使用 @rollup/plugin-node-resolve 插件实现的。

3. 打包成其它格式

上面的例子通过指定 format=esm,指定了 Rollup 打包为 ES 模块格式,也可以通过指定其它格式打包,支持的格式包括:

format 说明
1 esm ES Modules
2 cjs CommonJS
3 iife 立即执行函数
4 amd AMD
5 umd UMD

修改一下上面的 m2/rollup.config.js 就可以打包成各种格式:

import resolve from "@rollup/plugin-node-resolve";

export default {
  ...,
  output: [
    {
      format: "esm",
      file: "dist/bundle+m1.js"
    },
    {
      format: "cjs",
      file: "dist/bundle+m1.cjs.js"
    },
    {
      format: "iife",
      file: "dist/bundle+m1.iife.js",
      // 【可选配置】If you do not supply "output.name", you may not be able to access the exports of an IIFE bundle.
      name: "m2"
    },
    {
      format: "amd",
      file: "dist/bundle+m1.amd.js"
    },
    {
      format: "umd",
      file: "dist/bundle+m1.umd.js",
      // umd 格式必须指定 name,否则报错
      name: "m2"
    }
  ],
  ...
};

重新运行 yarn workspace m2 build-c,各种格式的打包结果汇总如下:

3.1 esm

const f1 = () => "m1f1";
const f = () => "m2f>" + f1();
export { f };

3.2 cjs

'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const f1 = () => "m1f1";
const f = () => "m2f>" + f1();
exports.f = f;

3.3 iife

var m2 = (function (exports) {
  'use strict';
  const f1 = () => "m1f1";
  const f = () => "m2f>" + f1();
  exports.f = f;
  return exports;
}({}));

3.4 amd

define(['exports'], function (exports) { 'use strict';
  const f1 = () => "m1f1";
  const f = () => "m2f>" + f1();
  exports.f = f;
  Object.defineProperty(exports, '__esModule', { value: true });
});

3.5 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.m2 = {}));
}(this, (function (exports) { 'use strict';
  const f1 = () => "m1f1";
  const f = () => "m2f>" + f1();
  exports.f = f;
  Object.defineProperty(exports, '__esModule', { value: true });
})));

相关文章

网友评论

      本文标题:使用 Rollup 开发组件:打包基础

      本文链接:https://www.haomeiwen.com/subject/zuuuxhtx.html