10分钟快速入门rollup.js

栏目: Node.js · 发布时间: 5年前

内容简介:rollup.js是Javascript的ES模块打包器,我们熟知的Vue、React等诸多知名框架或类库都通过rollup.js进行打包。与Webpack偏向于应用打包的定位不同,rollup.js更专注于Javascript类库打包(虽然rollup.js也可以提供资源打包,但显然这不是它的强项)。在我们学习Vue和React等框架源码或者自己编写Javascript类库时,rollup.js是一条必经之路。rollup.js可以将我们自己编写的Javascript代码(通过插件可以支持更多语言,如T

rollup.js是Javascript的ES模块打包器,我们熟知的Vue、React等诸多知名框架或类库都通过rollup.js进行打包。与Webpack偏向于应用打包的定位不同,rollup.js更专注于Javascript类库打包(虽然rollup.js也可以提供资源打包,但显然这不是它的强项)。在我们学习Vue和React等框架源码或者自己编写Javascript类库时,rollup.js是一条必经之路。

rollup.js的工作原理

rollup.js可以将我们自己编写的Javascript代码(通过插件可以支持更多语言,如Tyepscript)与第三方模块打包在一起,形成一个文件,该文件可以是一个库(Library)或者一个应用(App),在打包过程中可以应用各类插件实现特定功能。下图揭示了rollup.js的运行机制:

10分钟快速入门rollup.js

rollup.js默认采用ES模块标准,我们可以通过rollup-plugin-commonjs插件使之支持CommonJS标准。

安装rollup.js

rollup.js的安装依赖于nodejs,之前的手记中我曾详细介绍如何通过nvm管理nodejs版本,需要了解的小伙伴可以点击这里

全局安装rollup.js

首先全局安装rollup:

npm i rollup -g
复制代码

rollup.js打包实例

安装成功后,我们尝试使用rollup做一个简单的案例,创建src目录:

mkdir src
复制代码

在src目录下创建a.js:

vim src/a.js
复制代码

写入如下代码,这个模块非常简单,仅仅对外暴露一个变量a:

const a = 1
export default a
复制代码

在src目录下再创建main.js:

vim src/main.js
复制代码

写入如下代码,这个模块会引入模块a,并对外暴露一个function:

import a from './a.js'
  
export default function() {
  console.log(a)
}
复制代码

通过rollup指令,我们可以快速地预览打包后的源码,这点和babel非常类似:

$ rollup src/main.js -f es

src/main.js  stdout...
const a = 1;

function main() {
  console.log(a);
}

export default main;
created stdout in 26ms
复制代码

需要注意的是rollup必须带有 -f 参数,否则会报错:

$ rollup src/main.js

src/main.js  stdout...
[!] Error: You must specify output.format, which can be one of 'amd', 'cjs', 'system', 'esm', 'iife' or 'umd'
https://rollupjs.org/guide/en#output-format-f-format
复制代码

rollup的报错提示非常棒,非常有利于我们定位错误和修复问题。通过上面的错误提示,我们了解到 -f 的值可以为'amd'、'cjs'、'system'、'esm'('es'也可以)、'iife'或'umd'中的任何一个。 -f 参数是 --format 的缩写,它表示生成代码的格式,amd表示采用AMD标准,cjs为CommonJS标准,esm(或es)为ES模块标准。接着我们把这段代码输出到一个文件中:

$ rollup src/main.js -f es -o dist/bundle.js

src/main.js  dist/bundle.js...
created dist/bundle.js in 29ms
复制代码

参数 -o 指定了输出的路径,这里我们将打包后的文件输出到dist目录下的bundle.js,这个文件内容与我们之前预览的内容是完全一致的。我们再输出一份CommonJS格式的代码:

$ rollup src/main.js --format cjs --output.file dist/bundle-cjs.js

src/main.js  dist/bundle-cjs.js...
created dist/bundle-cjs.js in 27ms
复制代码

参数 --output.file-o 的全称,它们是等价的,输出后我们在dist目录下会多一个bundle-cjs.js文件,查看这个文件的内容:

'use strict';
  
const a = 1;

function main() {
  console.log(a);
}

module.exports = main;
复制代码

可以看到代码采用CommonJS标准编写,并且将a.js和main.js两个文件进行了融合。

验证rollup.js打包结果

在打包成功后,我们尝试运行dist/bundle-cjs.js代码:

$ node
> const m = require('./dist/bundle-cjs.js')
> m()
1 
复制代码

我们接着尝试运行之前输出的ES标准代码dist/bundle.js,由于nodejs并不支持ES标准,直接运行会报错:

$ node
> require('./dist/bundle.js')()
/Users/sam/Desktop/rollup-test/dist/bundle.js:7
export default main;
^^^^^^

SyntaxError: Unexpected token export
复制代码

babel为我们提供了一个工具:babel-node,它可以在运行时将ES标准的代码转换为CommonJS格式,从而使得运行ES标准的代码成为可能,首先全局安装babel-node及相关工具,@babel/node包含babel-node,@babel/cli包含babel,而这两个 工具 都依赖@babel/core,所以建议都安装:

npm i @babel/core @babel/node @babel/cli -g
复制代码

这里要注意的是babel 7改变了npm包的名称,之前的babel-core和babel-cli已经被弃用,所以安装老版本babel的同学建议先卸载:

npm uninstall babel-cli babel-core -g
复制代码

然后到代码的根目录下,初始化项目:

npm init
复制代码

一路回车后,在代码根目录下创建babel的配置文件.babelrc,写入如下配置

{
  "presets": ["@babel/preset-env"]
}
复制代码

完成babel配置后安装babel的依赖:

npm i -D @babel/core @babel/preset-env
复制代码

尝试通过babel编译代码:

$ babel dist/bundle.js 
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var a = 1;

function main() {
  console.log(a);
}

var _default = main;
exports.default = _default;
复制代码

可以看到ES模块代码被编译成了CommonJS格式,下面通过babel-node运行代码:

$ babel-node 
> require('./dist/bundle.js')
{ default: [Function: main] }
> require('./dist/bundle.js').default()
1
复制代码

注意babel会认为 export default function() 是一个名称为default的函数,如果想更改这个函数名称,可以修改main.js:

import a from './a.js'
  
export function test() {
  console.log(a)
}
复制代码

重写打包后通过babel-node运行:

$ rollup -f es --file dist/bundle.js src/main.js 

src/main.js  dist/bundle.js...
created dist/bundle.js in 26ms

$ babel-node 
> require('./dist/bundle.js').test()
1
复制代码

注意这里的 --file 定价于 -o--output.file ,通过上述案例,我们完成了rollup打包的基本操作,并验证了打包结果。但很多时候我们不会这样操作,因为直接使用命令行功能单一,而且无法使用插件,所以我们需要借助配置文件来操作。

rollup.js配置文件

首先在代码根目录下创建rollup.config.js文件:

touch rollup.config.js
复制代码

写入如下配置:

export default {
  input: './src/main.js',
  output: [{
    file: './dist/index-cjs.js',
    format: 'cjs',
    banner: '// welcome to imooc.com',
    footer: '// powered by sam'
  }, {
    file: './dist/index-es.js',
    format: 'es',
    banner: '// welcome to imooc.com',
    footer: '// powered by sam'
  }]
}
复制代码

rollup的配置文件非常容易理解,这里有几点需要说明:

  • rollup的配置文件需要采用ES模块标准编写
  • input表示入口文件的路径(老版本为entry,已经废弃)
  • output表示输出文件的内容,它允许传入一个对象或一个数组,当为数组时,依次输出多个文件,它包含以下内容:
    • output.file:输出文件的路径(老版本为dest,已经废弃)
    • output.format:输出文件的格式
    • output.banner:文件头部添加的内容
    • output.footer:文件末尾添加的内容

通过 rollup -c 指令进行打包,rollup.js会自动寻找名称为rollup.config.js的配置文件:

$ rollup -c

./src/main.js  ./dist/index-cjs.js, ./dist/index-es.js...
created ./dist/index-cjs.js, ./dist/index-es.js in 13ms
复制代码

查看dist/index-es.js文件:

// welcome to imooc.com
const a = 1;

function test() {
  console.log(a);
}

export { test };
// powered by sam
复制代码

代码的内容与命令行生成的无异,但头部和末尾添加了自定义的注释信息。接着我们修改配置文件的名称,并通过 -c 参数指定配置文件进行打包:

$ mv rollup.config.js rollup.config.dev.js
$ rollup -c rollup.config.dev.js 

./src/main.js  ./dist/index-cjs.js, ./dist/index-es.js...
created ./dist/index-cjs.js, ./dist/index-es.js in 13ms
复制代码

rollup.js api打包

编写rollup.js配置

很多时候命令行和配置文件的打包方式无法满足需求,我们需要更加个性化的打包方式,这时我们可以考虑通过rollup.js的api进行打包,创建rollup-input-options.js,这是输入配置,我们单独封装一个模块,提高复用性和可扩展性:

touch rollup-input-options.js
复制代码

在输入配置文件中加入以下内容,需要注意的是这个文件必须为CommonJS格式,因为需要使用nodejs来执行:

module.exports = {
  input: './src/main.js'
}
复制代码

再添加一个输出配置文件:

touch rollup-output-options.js
复制代码

在输出配置文件我们仍然使用一个数组,实现多种文件格式的输出,需要注意的是umd格式必须指定模块的名称,通过name属性来实现:

module.exports = [{
  file: './dist/index-cjs.js',
  format: 'cjs',
  banner: '// welcome to imooc.com',
  footer: '// powered by sam'
}, {
  file: './dist/index-es.js',
  format: 'es',
  banner: '// welcome to imooc.com',
  footer: '// powered by sam',
}, {
  file: './dist/index-amd.js',
  format: 'amd',
  banner: '// welcome to imooc.com',
  footer: '// powered by sam',
}, {
  file: './dist/index-umd.js',
  format: 'umd',
  name: 'sam-umd', // 指定文件名称
  banner: '// welcome to imooc.com',
  footer: '// powered by sam',
}]
复制代码

编写rollup.js build代码

接下来我们要在当前项目中安装rollup库:

npm i -D rollup
复制代码

创建一个rollup-build文件,通过这个文件来调用rollup的api:

touch rollup-build.js
复制代码

rollup-build的源码如下:

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

async function rollupBuild(input, output) {
  const bundle = await rollup.rollup(input) // 根据input配置进行打包
  console.log(`正在生成:${output.file}`)
  await bundle.write(output) // 根据output配置输出文件
  console.log(`${output.file}生成成功!`)
}

(async function () {
  for (let i = 0; i < outputOptions.length; i++) {
    await rollupBuild(inputOptions, outputOptions[i])
  }
})()
复制代码

代码的核心有两点:

rollup.rollup(input)
bundle.write(output)

这里我们还可以通过async和await实现同步操作,因为 bundle.write(output) 是异步的,会返回Promise对象,我们可以借助async机制实现按配置顺序依次打包。执行rollup-build文件:

$ node rollup-build.js 
正在生成:./dist/index-cjs.js
./dist/index-cjs.js生成成功!
正在生成:./dist/index-es.js
./dist/index-es.js生成成功!
正在生成:./dist/index-amd.js
./dist/index-amd.js生成成功!
正在生成:./dist/index-umd.js
./dist/index-umd.js生成成功!
复制代码

查看dist/index-umd.js文件:

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
  (factory((global['sam-umd'] = {})));
}(this, (function (exports) {
	// ...
}
复制代码

可以看到index-umd.js文件中在global全局变量中添加了sam-umd属性,这就是我们之前需要在umd配置中添加name属性的原因。

总结

本文向大家介绍了rollup.js的三种打包方式:命令行、配置文件和API,在下一篇教程中我将继续为大家介绍更多rollup.js的特性,如Tree-shaking、watch等,还会详细演示各种插件的用途及用法,敬请关注。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Essential C++中文版

Essential C++中文版

李普曼 (Stanley B.Lippman) / 侯捷 / 电子工业出版社 / 2013-8-1 / CNY 65.00

本书以四个面向来表现C++的本质:procedural(面向过程的)、generic(泛型的)、object-based(基于对象的)、objectoriented(面向对象的)。全书围绕一系列逐渐繁复的程序问题,以及用以解决这些问题的语言特性来组织。循此方式,你将不只学到C++的功能和结构,也可学到它们的设计目的和基本原理。 本书适合那些已经开始从事软件设计,又抽不出太多时间学习新技术的程......一起来看看 《Essential C++中文版》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换