preface

In this tutorial, we will continue to explore the advanced techniques of rollup.js. If you want to read the conclusion directly, you can read the last chapter.

A rollup. Js plug-in

The rollup.js plug-in has a pluggable design that helps us enhance the basic functionality of rollup.js. Here I highlight four of the most commonly used rollup.js plug-ins.

Resolve the plugin

Why do you need the Resolve plug-in?

In the previous tutorial, the objects we packaged were local JS code and libraries, but in real development, it is unlikely that all libraries will be local and we will download remote libraries via NPM. Rollup.js: rollup.js: rollup.js: rollup.js: rollup.js: rollup.js: rollup.js

npm i -S sam-test-data
Copy the code

The sam-test-data library provides a UMD module by default, which exposes two variables A and B and a random function. A is a random integer between 0 and 9, and B is a random integer between 0 and 99. The parameter of the random function is an integer, such as 100. Return a random integer between 0 and 99 to create a test plug-in code folder locally:

mkdir src/plugin
Copy the code

Create test code:

touch src/plugin/main.js
Copy the code

Write the following code:

import * as test from 'sam-test-data'
console.log(test)
export default test.random
Copy the code

Try running the code directly from babel-Node without using rollup.js package:

babel-node
> require('./src/plugin/main.js')
{ a: 1, b: 17, random: [Function: random] }
{ default: [Function: random] }
> require('./src/plugin/main.js').default(100)
41
Copy the code

As you can see that the code works, let’s try to package the code with rollup.js and add a new configuration file:

touch rollup.plugin.config.js
Copy the code

Write the following:

import { comment } from './comment-helper-es'

export default {
  input: './src/plugin/main.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'.banner: comment('welcome to imooc.com'.'this is a rollup test project'),
    footer: comment('powered by sam'.'copyright 2018')}, {file: './dist/index-plugin-es.js'.format: 'es'.banner: comment('welcome to imooc.com'.'this is a rollup test project'),
    footer: comment('powered by sam'.'copyright 2018')}}]Copy the code

Here I provide a comment-helper-es module, which exposes a comment method, automatically reads our parameters, and helps generate comments. At the same time, I add equal length delimiters above and below the comments, which can be directly used by interested partners:

export function comment() {
  if (arguments.length === 0) {
    return // Return if the argument is 0
  }
  let maxlength = 0
  for (let i = 0; i < arguments.length; i++) {
    const length = arguments[i].toString().length
    maxlength = length > maxlength ? length : maxlength // Get the longest parameter
  }
  maxlength = maxlength === 0 ? maxlength : maxlength + 1 // Add 1 to the length of the longest argument for aesthetic reasons
  let seperator = ' '
  for (let i = 0; i < maxlength; i++) {
    seperator += '=' // Generate delimiters based on the length of the argument
  }
  const c = []
  c.push('/**\n') // Add a comment header
  c.push(The '*' + seperator + '\n') // Add a comment separator
  for (let i = 0; i < arguments.length; i++) {
    c.push(The '*' + arguments[i] + '\n') // Add parameters
  }
  c.push(The '*' + seperator + '\n') // Add a comment separator
  c.push('* * /) // Add a comment tail
  return c.join(' ') // Merge the argument to a string
}
Copy the code

Package via rollup.js:

$rollup -c rollup.plugin.config.js./ SRC /plugin/main.js →./dist/ index-plugin-js,./dist/index-plugin-es.js... (!) Unresolved dependencies https://rollupjs.org/guide/en#warning-treating-module-as-external-dependency
sam-test-data (imported by src/plugin/main.js)
created ./dist/index-plugin-cjs.js, ./dist/index-plugin-es.js in 13ms
Copy the code

Dist /index-plugin-es.js (dist/index-plugin-es.js, dist/index-plugin-es.js)

/** * ============================== * welcome to imooc.com * this is a rollup test project * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * * /
import * as test from 'sam-test-data';
import { random } from 'sam-test-data';

console.log(test);

var main = random;

export default main;
/** * =============== * powered by sam * copyright 2018 * =============== **/
Copy the code

It is almost the same as the original code we wrote, except that the random function is obtained separately from Sam-test-data by es6 destructuring assignment, and then assigned to the variable main and exposed. Imagine if we were writing a Javascript class library and users had to manually download all of the library’s dependencies when referencing it. To solve this problem, by merging the source code we wrote with our dependent third-party libraries, rollup.js provides us with the resolve plug-in.

How to use the resolve plug-in

First, install the Resolve plug-in:

npm i -D rollup-plugin-node-resolve
Copy the code

Modify configuration file rollup.plugin.config.js:

import resolve from 'rollup-plugin-node-resolve'

export default {
  input: './src/plugin/main.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'
  }, {
    file: './dist/index-plugin-es.js'.format: 'es'}].plugins: [
    resolve()
  ]
}
Copy the code

Repack:

$rollup -c rollup.plugin.config.js./ SRC /plugin/main.js →./dist/ index-plugin-js,./dist/index-plugin-es.js... created ./dist/index-plugin-cjs.js, ./dist/index-plugin-es.jsin 28ms
Copy the code

Dist /index-plugin-es.js: dist/index-plugin-es.js: dist/index-plugin-es.js

const a = Math.floor(Math.random() * 10);
const b = Math.floor(Math.random() * 100);
function random(base) {
  if (base && base % 1= = =0) {
    return Math.floor(Math.random() * base) 
  } else {
    return 0}}var test = /*#__PURE__*/Object.freeze({
  a: a,
  b: b,
  random: random
});

console.log(test);

var main = random;

export default main;
Copy the code

It is clear that the source code for the Sam-test-data library is already integrated with our source code.

tree-shaking

SRC /plugin/main.js SRC /plugin/main.js

import * as test from 'sam-test-data'
export default test.random
Copy the code

Remove console.log(test) from source code and repackage:

rollup -c rollup.plugin.config.js
Copy the code

Dist /index-plugin-es.js dist/index-plugin-es.js

function random(base) {
  if (base && base % 1= = =0) {
    return Math.floor(Math.random() * base) 
  } else {
    return 0}}var main = random;

export default main;
Copy the code

We find that the definition of variables A and B is missing because they are not used in the source code. This is the well-known tree-shaking mechanism of the ES module, which dynamically cleans out unused code and makes it leaner, thus making our library load faster (naturally faster with less capacity).

External properties

In some cases, we need to use the external attribute to tell rollup. Js which libraries are external and modify the rollup. Js configuration file:

import resolve from 'rollup-plugin-node-resolve'

export default {
  input: './src/plugin/main.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'
  }, {
    file: './dist/index-plugin-es.js'.format: 'es'}].plugins: [
    resolve()
  ],
  external: ['sam-test-data']}Copy the code

Repack:

rollup -c rollup.plugin.config.js
Copy the code

Dist /index-plugin-es.js

import { random } from 'sam-test-data';

var main = random;

export default main;
Copy the code

You can see that the sam-test-data library is treated as an external library despite the use of the resolve plug-in

Commonjs plug-in

Why do WE need the CommonJS plug-in?

Rollup.js does not support CommonJS modules by default. Here I wrote a CommonJS module for testing. The contents of this module are exactly the same as sam-test-data, except that the former uses the CommonJS specification.

npm i -S sam-test-data-cjs
Copy the code

Create a new code file:

touch src/plugin/main-cjs.js
Copy the code

Write the following code:

import test from 'sam-test-data-cjs'
console.log(test)
export default test.random
Copy the code

This code is very simple. Next modify the rollup.js configuration file:

import resolve from 'rollup-plugin-node-resolve'

export default {
  input: './src/plugin/main-cjs.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'
  }, {
    file: './dist/index-plugin-es.js'.format: 'es'}].plugins: [
    resolve()
  ]
}
Copy the code

Perform packaging:

Rollup -c rollup.plugin.config.js./ SRC /plugin/main-cjs.js →./dist/index-plugin-cjs.js,./dist/index-plugin-es.js... [!]  Error:'default'Is not exported by node_modules / _sam - [email protected] @ Sam - test - data - CJS/index. Js https://rollupjs.org/guide/en#error-name-is-not-exported-by-module-
src/plugin/main-cjs.js (1:7)
1: import test from 'sam-test-data-cjs'
          ^
Copy the code

As you can see, rollup.js does not recognize CommonJS modules by default, so we need to use the CommonJS plugin to solve this problem.

How to use the CommonJS plugin

Install the CommonJS plugin first:

npm i -D rollup-plugin-commonjs
Copy the code

Modify the rollup.js configuration file:

import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'

export default {
  input: './src/plugin/main-cjs.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'
  }, {
    file: './dist/index-plugin-es.js'.format: 'es'}].plugins: [
    resolve(),
    commonjs()
  ]
}
Copy the code

Repacking:

rollup -c rollup.plugin.config.js
Copy the code

Dist /index-plugin-es.js

const a = Math.floor(Math.random() * 10);
const b = Math.floor(Math.random() * 100);
function random(base) {
  if (base && base % 1= = =0) {
    return Math.floor(Math.random() * base) 
  } else {
    return 0}}var _samTestDataCjs_0_0_1_samTestDataCjs = {
  a, b, random
};

console.log(_samTestDataCjs_0_0_1_samTestDataCjs);
var mainCjs = _samTestDataCjs_0_0_1_samTestDataCjs.random;

export default mainCjs;
Copy the code

You can see that the CommonJS module is integrated into the code, and try to execute the packaged code via babel-Node:

babel-node 
> require('./dist/index-plugin-es')
{ a: 7, b: 45, random: [Function: random] }
{ default: [Function: random] }
> require('./dist/index-plugin-es').default(1000)
838
Copy the code

The code execution is successful, indicating that our code packaging is successful.

CommonJS and tree – shaking

SRC /plugin/main-cjs.js to verify that the CommonJS module supports tree-shaking:

import test from 'sam-test-data-cjs'
export default test.random
Copy the code

As in the resolve tree-shaking example, remove console.log(test), re-package, and then look at the package source:

const a = Math.floor(Math.random() * 10);
const b = Math.floor(Math.random() * 100);
function random(base) {
  if (base && base % 1= = =0) {
    return Math.floor(Math.random() * base) 
  } else {
    return 0}}var _samTestDataCjs_0_0_1_samTestDataCjs = {
  a, b, random
};

var mainCjs = _samTestDataCjs_0_0_1_samTestDataCjs.random;

export default mainCjs;
Copy the code

The CommonJS module does not support tree-shaking, so it is recommended that you use the ES module when using rollup.js to get more streamlined code.

UMD and tree – shaking

The UMD module is similar to CommonJS and does not support tree-shaking. Here is a test module for UMD, sam-test-data-umD. Sam-test-data is also a UMD module. Why does it support tree-shaking? Let’s open sam-test-data’s package.json to find out:

{
  "name": "sam-test-data"."version": "0.0.4"."description": "provide test data"."main": "dist/sam-test-data.js"."module": "dist/sam-test-data-es.js"
}
Copy the code

You can see that the main attribute points to dist/sam-test-data.js, which is a UMD module, but the module attribute points to dist/sam-test-data-es.js, which is an ES module. Rollup.js by default finds and loads the module pointed to by the Module property first. So the ES module of Sam-test-Data is loaded first to support the tree-shaking feature. Let’s take a look at the official description of rollup.js:

Point to the current compiled version in the main property of the package.json file. If your package.json also has a module field, ES6-Aware tools like Rollup and WebPack 2 will import the ES6 module version directly.

Babel plug-in

Why do you need the Babel plug-in?

Create a new file main-es.js in the SRC /plugin directory:

touch src/plugin/main-es.js
Copy the code

Write the following code:

import { a, b, random } from 'sam-test-data-es'

console.log(a, b, random)
export default (base) => {
  return random(base)
}
Copy the code

New ES6 features are adopted in the code: arrow function, modify configuration file:

import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'

export default {
  input: './src/plugin/main-es.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'
  }, {
    file: './dist/index-plugin-es.js'.format: 'es'}].plugins: [
    resolve(),
    commonjs()
  ]
}
Copy the code

Repacking:

rollup -c rollup.plugin.config.js 
Copy the code

Dist /index-plugin-es.js

var mainEs = (base) = > {
  return random(base)
};

export default mainEs;
Copy the code

As you can see, the arrow function is retained, and such code will not run in an environment that does not support ES6. We expect Babel to be used for code conversion during rollup.js packaging, so we need the Babel plug-in.

How to use the Babel plug-in

Install the Babel plugin first:

npm i -D rollup-plugin-babel
Copy the code

Modify the configuration file to add a reference to the Babel plug-in:

import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import babel from 'rollup-plugin-babel'

export default {
  input: './src/plugin/main-es.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'
  }, {
    file: './dist/index-plugin-es.js'.format: 'es'}].plugins: [
    resolve(),
    commonjs(),
    babel()
  ]
}
Copy the code

Repack:

rollup -c rollup.plugin.config.js
Copy the code

Dist /index-plugin-es.js dist/index-plugin-es.js

var mainEs = (function (base) {
  return random(base);
});

export default mainEs;
Copy the code

You can see that the arrow function is converted to function, and the Babel plug-in works fine.

Json plug-in

Why do YOU need a JSON plug-in

Create a new file main-json.js under SRC /plugin:

touch src/plugin/main-json.js
Copy the code

Import package.json as a module and print the name and main properties in package.json:

import json from '.. /.. /package.json'

console.log(json.name, json.main)
Copy the code

Using able-node, try main-json.js:

$ babel-node src/plugin/main-json.js 
rollup-test index.js
Copy the code

You can see that the name and main fields are printed out, and the babel-Node correctly recognizes the JSON module. Modify the rollup.js configuration file below:

import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import babel from 'rollup-plugin-babel'

export default {
  input: './src/plugin/main-json.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'
  }, {
    file: './dist/index-plugin-es.js'.format: 'es'}].plugins: [
    resolve(),
    commonjs(),
    babel()
  ]
}
Copy the code

Repack:

$rollup -c rollup.plugin.config.js./ SRC /plugin/ main-json-js →./dist/ index-plugin-js, ./dist/index-plugin-es.js... [!]  Error: Unexpected token (Note that you need rollup-plugin-json to import JSON files)Copy the code

You can see that rollup.js does not support importing JSON modules by default, so we need to use json plug-ins to support this.

How to use the JSON plug-in

Download json plugin:

npm i -D rollup-plugin-json
Copy the code

Modifying a configuration file:

import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import babel from 'rollup-plugin-babel'
import json from 'rollup-plugin-json'

export default {
  input: './src/plugin/main-json.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'
  }, {
    file: './dist/index-plugin-es.js'.format: 'es'}].plugins: [
    resolve(),
    commonjs(),
    babel(),
    json()
  ]
}
Copy the code

Repack:

rollup -c rollup.plugin.config.js
Copy the code

Dist /index-plugin-cjs.js json file is parsed as an object for processing:

var name = "rollup-test";
var version = "1.0.0";
var description = "";
var main = "index.js";
var scripts = {
	test: "echo \"Error: no test specified\" && exit 1"
};
var author = "";
var license = "ISC";
var devDependencies = {
	"@babel/core": "^ 7.1.6." "."@babel/plugin-external-helpers": "^ 7.0.0." "."@babel/preset-env": "^ 7.1.6." ".rollup: "^ 0.67.3"."rollup-plugin-babel": "^ 4.0.3"."rollup-plugin-commonjs": "^ 9.2.0"."rollup-plugin-json": "^ 3.1.0"."rollup-plugin-node-resolve": "^ 3.4.0"
};
var dependencies = {
	epubjs: "^ 0.3.80".loadsh: "^ 0.0.3"."sam-test-data": "^ 0.0.4"."sam-test-data-cjs": "^ 0.0.1." "."sam-test-data-es": "^ 0.0.1." "."sam-test-data-umd": "^ 0.0.1." "
};
var json = {
	name: name,
	version: version,
	description: description,
	main: main,
	scripts: scripts,
	author: author,
	license: license,
	devDependencies: devDependencies,
	dependencies: dependencies
};

console.log(json.name, json.main);
Copy the code

Uglify plug-in

The Uglify plug-in can help us further reduce the size of the code, first installing the plug-in:

npm i -D rollup-plugin-uglify
Copy the code

Modify the rollup.js configuration file:

import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import babel from 'rollup-plugin-babel'
import json from 'rollup-plugin-json'
import { uglify } from 'rollup-plugin-uglify'

export default {
  input: './src/plugin/main.js'.output: [{
    file: './dist/index-plugin-cjs.js'.format: 'cjs'}].plugins: [
    resolve(),
    commonjs(),
    babel(),
    json(),
    uglify()
  ]
}
Copy the code

The uglify plugin does not support the ES module and ES6 syntax, so it can only be packaged in non-ES format. If you encounter ES6 syntax, you will get an error:

$rollup -c rollup.plugin.config.js./ SRC /plugin/main.js →./dist/ index-plugin-js,./dist/index-plugin-es.js... 19 | var main = random; 20 | | > 21exportdefault main; | ^ Unexpected token: keyword (default) [!]  (uglify plugin) Error: Unexpected token: keyword (default)Copy the code

So here we use sam-test-data test, because this module is compiled using Babel, the other several modules are not supported by Uglify (because the other modules use const, const is also an ES6 feature, uglify does not support). Use the Babel plugin to compile your own library. After the configuration is complete, pack it again:

$ rollup -c rollup.plugin.config.js 

./src/plugin/main.js → ./dist/index-plugin-cjs.js...
created ./dist/index-plugin-cjs.js in 679ms
Copy the code

Dist /index-plugin-cjs.js

"use strict";var a=Math.floor(10*Math.random()),b=Math.floor(100*Math.random());function random(a){return a&&a%1= =0?Math.floor(Math.random()*a):0}var test=Object.freeze({a:a,b:b,random:random});console.log(test);var main=random;module.exports=main;
Copy the code

You can see that the code has been minimized and the size has been reduced a lot.

rollup.js watch

Command line mode

The watch mode of rollup.js supports monitoring code changes and automatically performs packaging once the code is modified. It is very convenient to use it by adding –watch after the packaging instruction:

$rollup -c rollup.plugin.config.js --watch rollup v0.67.1 bundles./ SRC /plugin/main-json.js → dist/index-plugin-cjs.js,  dist/index-plugin-es.js... created dist/index-plugin-cjs.js, dist/index-plugin-es.jsin 24ms

[2018-11-20 22:26:24] waiting for changes...
Copy the code

The API schema

Rollup. js allows us to start watch mode through the API and create the following files in the project root directory:

  • Rollup-watching-input-options. js: input configuration
  • Rollup-watching-output-options. js: outputs the configuration
  • Rollup-watching-options. js: listens for configuration
  • Rollup-watch. js: Call the API of rollup.js to start the watch mode

To enable Node to execute our program, we use the CommonJS specification, rollup-watching-input-options. js:

const json = require('rollup-plugin-json')
const resolve = require('rollup-plugin-node-resolve')
const commonjs = require('rollup-plugin-commonjs')
const babel = require('rollup-plugin-babel')
const uglify = require('rollup-plugin-uglify').uglify

module.exports = {
  input: './src/plugin/main.js'.plugins: [
    json(),
    resolve({
      customResolveOptions: {
        moduleDirectory: 'node_modules' // Only libraries in node_modules are processed
      }
    }),
    babel({
      exclude: 'node_modules/**' / / node_modules ruled out
    }),
    commonjs(),
    uglify() // Code compression]}Copy the code

Rollup-watch-output-options. js: rollup-watch-output-options.js: rollup-watch-output-options.js

module.exports = [{
  file: './dist/index-cjs.js'.format: 'cjs'.name: 'sam-cjs'
}]
Copy the code

Rollup-watching-options. js looks like this:

module.exports = {
  include: 'src/**'.// Listen to the folder
  exclude: 'node_modules/**' // Exclude listening folders
}
Copy the code

Rollup-watch.js code is as follows:

const rollup = require('rollup')
const inputOptions = require('./rollup-watch-input-options')
const outputOptions = require('./rollup-watch-output-options')
const watchOptions = require('./rollup-watch-options')

constoptions = { ... inputOptions,output: outputOptions,
  watchOptions
} // Generate options for rollup

const watcher = rollup.watch(options) // Invoke the ROLLup API to start listening

watcher.on('event', event => {
  console.log('Repacking... ', event.code)
}) // Handle listening events

// watcher.close() // Manually close the listener
Copy the code

Start listening directly from Node:

$node rollup-watch.js START repacking... BUNDLE_START repack... BUNDLE_END repack... ENDCopy the code

After modifying the SRC /plugin/main.js source code, rollup.js will automatically package the code.

conclusion

Rollup.js plugins, tree-shaking mechanism, and Watch mode are covered in detail in this tutorial.

  • A rollup. Js plug-in
    • Resolve plug-in: Integrate external modules
    • Commonjs plug-in: Support for CommonJS modules
    • Babel plug-in: Compiles ES6 syntax to be recognized by earlier browsers
    • Json plug-in: Support JSON module
    • Uglify: Code minimization packaging (ES module not supported)
  • Tree-shaking: It is supported only by THE ES module
  • Watch mode: supports command line and API modes to monitor code changes in real time