解读官网,通俗易懂地学习Rollup。

目录

  1. 介绍
    1. 是什么
    2. 与webpack对比
  2. 常见问题
  3. 基本使用
    1. 快速上手
    2. 使用方式
    3. 常用插件
    4. 核心功能
  4. ES模块使用
    1. 导入
    2. 导出
  5. 集成其他工具
  6. Javascript API
  7. 基本款模板
  8. 参考资料

介绍

  • 是什么

    Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。

    告别生撸前端代码,使用es6新语法,模块化等技术优雅写前端代码。

    Rollup 对代码模块使用新的标准化格式,这些标准都包含在 JavaScript 的 ES6 版本中,而不是以前的特殊解决方案,如 CommonJS 和 AMD。

    在使用rollup构建时,代码中引入模块只遵守ES模块规范。

  • 与webpack对比

    webpack:

    • 适合构建应用
    • 支持代码拆分,支持代码异步加载、按需加载,支持热加载、开发环境本地服务调试

    rollup:

    • 适合构建lib库
    • 打包出来的bundle比较干净,执行快,没有冗余代码
    • 不支持代码拆分(最新的版本引入插件已经支持)、热加载、开发环境本地服务调试、不支持代码异步加载、按需加载
    • 所有资源放在同一个地方,一次性加载
    1. 两者都支持Tree-shaking,但这个概念最初是由rollup引入的。
    2. rollup并不支持代码拆分、热加载、开发环境本地服务调试
    3. 对于类库开发,只有 js,而没有其他的静态资源文件,webpack有些大材小用,使用rollup更合适
    4. 两者都支持导出时都支持各种模块规范
    5. 如果你的项目中引入了许多CommonJs规范的模块,也推荐使用webpack

常见问题

  • 什么是 ‘tree-shaking’?

    1. 打包过程中自动删除代码中为引用的冗余代码
    2. 删除部分逻辑简单的计算代码,如:var a = 1; var b =2; var c = a + b; 打包结果:var c = 3
  • 如果执行命令行参数和配置文件存在相同参数配置,优先选择哪一方?

    优先选择命令行

  • 自己写lib库时,可以引入的模块类型都有哪些,如何引入?

    首先说一下整体流程:rollup将所有的模块代码引入方式改成import,然后在使用babel编译出兼容代码

    所有模块类型都可以引入,包括:

    1. 自己写的ES模块:直接引入
    2. node_modules中的第三方模块:见下个问题
  • 源代码中如何引入node_modules中的模块?

    不管是以require方式还是import方式导入,打包出来的bundle中都还是原本的require/import语句,并且打包结果并未引入到node_modules中的第三方资源。

    此时我们需要先想办法将node_Module中的资源先提取出来,放到最后的打包的bundle中。(先不考虑在如何浏览器中运行)

    rollup并不知道如何打破常规去处理node_modules中的依赖,需要使用 rollup-plugin-node-resolve 插件,告诉rollup如何去查找外部模块(node_modules中的模块) 找到之后,再去解析。

    至此,我们仅仅将允许以ES模块(如:the-answer 模块)类型引入的第三方依赖资源打包到bundle中。

    但是目前,npm中的大多数包都是以CommonJS模块的形式出现的。 在它们更改之前,我们需要将CommonJS模块转换为 ES2015 供 Rollup 处理。

    比如我们此时自己打包出一个只遵守Commonjs规范的包mock-lib。

    在源代码中使用import语法引入 ,然后打包,会报错。

    因为此时这个第三方包只能通过require方式引入。

    即使改成require方式引入 ,打包完成,也只能在node中运行 。

    如果我们自己打包出一个只遵守umd规范的包 mock-lib,结果同上。

    那我们到底如果引入外部的只支持CommonJs规范的模块呢?

    需要一个插件 rollup-plugin-commonjs ,帮我们解析,我们源代码中引入的,只遵循commonjs规范的第三方包,此时源代码中,我们只需使用import语法引入即可。

    注意:我们源代码中,只支持ES模块规范,导入只用import

  • 为什么ES模块比CommonJS更好?

    ES模块是一个官方标准,也是JavaScript代码结构的明确前进之路,而CommonJS模块是一种特殊的临时解决方案,作为ES模块被提出之前作为权宜之计。ES模块允许静态分析,这有助于tree-shaking等优化,并提供循环引用和实时绑定等高级功能。

  • UMD规范内部实现?

    先判断运行环境是否支持cjs,然后判断是否支持amd,如果都不支持,则使用iife规范,生成一个全局变量

基本使用

  • 快速上手
    1
    cnpm install rollup -g

    默认假设应用程序入口起点的名称为 main.js,并且你想要所有 import 的依赖(all imports)都编译到一个名为 bundle.js 的单个文件中。

    浏览器: rollup main.js --file bundle.js --format iife

    Node: rollup main.js --file bundle.js --format cjs

    通用: rollup main.js --file bundle.js --format umd --name "myBundle"

    1. 一句话总结:以为入口文件,以哪种模块规范输出,输出名字为的文件。
    2. 浏览器环境下,还不识别import语法,所以将打包出来的lib,以iife形式输出一个挂载在window上的全局对象。
    3. Node环境下,只支持CommonJs规范,所以以cjs类型输出。
  • 使用方式
    • 使用命令行
    • 使用配置文件
    • 使用Javascript API 调用

    你必须使用配置文件才能执行以下操作:

    1. 把一个项目打包,然后输出多个文件

    2. 使用Rollup插件

  • 常用插件
    • rollup-plugin-json: 从json文件中读取数据
    • rollup-plugin-node-resolve:解析外部模块
    • rollup-plugin-commonjs:解析只遵循CommonJs规范的模块
    • rollup-plugin-typescript:打包ts
  • 核心功能

    input、output、plugin、external详见官网

ES模块使用

导入导出是两码事儿,没有任何对应的关系

导入的模块不能被重新分配(不能被修改 ) 否则打包编译不过去

  • 导入
    1. 命名导入:

      import { something } from './module.js';

      import { something as somethingElse } from './module.js';

    2. 命名空间导入:

      import * as module from './module.js'

    3. 默认导入:

      import something from './module.js';

    4. 空导入:

      import './module.js';

      应用于腻子脚本`,这些脚本或工具只需要自执行,并且通常都是在我们的业务代码之前引入

  • 导出
    1. 命名导出

      export { something };

      export { something as somethingElse };

      export const something = true;

    2. 默认导出,仅当源模块只有一个导出时,才建议使用这种方法

      export default something;

集成其他工具

  • npm

  • Babel

    技术更新太快,详见英文官网

  • Gulp

    Rollup 返回 Gulp 能明白的 promise,所以集成是很容易的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    const gulp = require('gulp');
    const rollup = require('rollup');
    const rollupTypescript = require('rollup-plugin-typescript');
    gulp.task('build', async function () {
    const bundle = await rollup.rollup({
    input: './src/main.ts',
    plugins: [
    rollupTypescript()
    ]
    });
    await bundle.write({
    file: './dist/library.js',
    format: 'umd',
    name: 'library',
    sourcemap: true
    });
    });
  • Peer dependencies

    对等依赖关系:以Lodash为例

    有一种情况是,虽然我们引用了Loadsh的方法,但是不希望打包ladash代码,期待的是告知用户,我这个lib,需要依赖loadsh,你自己去下载(原因是用户的项目中可能也依赖loadsh,为避免最后打包上线的代码存在两份lodash)。

    指出应将哪些模块视为外部模块: external: ['lodash']

Javascript API

  • Rollup.rollup:如供gulp使用
  • Rollup.watch:监听文件变化,实时打包(不常用)

基本款模板

format代表着打包完成后以哪种类型的模块规范输出,如果是umd或iife,需要指定name属性,即生成全局变量的名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import json from 'rollup-plugin-json'
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
export default {
input: 'src/main.js',
output: {
file: 'lib/bundle.js',
format: 'umd',
name: 'zbw'
},
plugins: [
commonjs(),
json(),
resolve({
jsnext: true,
main: true
}),
babel({
exclude: 'node_modules/**',
})
],
external: ['lodash']
};

参考资料

由于中英文官网两者版本差距过大,墙裂推荐去英文官网:Rollup官网

demo