We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
项目中一直用的都是webpack,前一段需要开发几个类库供其他平台使用,本来打算继续用webpack的,但感觉webpack用来开发js库,不仅繁琐而且打包后的文件体积也比较大。正好之前看vue源码,知道vue也是通过rollup打包的。这次又是开发类库的,于是就快速上手了rollup。
webpack
js
vue
rollup
本篇文章是我有了一定的项目实践后,回过来给大家分享一下如何从零快速上手rollup。
系统的了解rollup之前,我们先来简单了解下What is rollup?
What is rollup?
关于rollup的介绍,官方文档已经写的很清楚了:
Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。
与Webpack偏向于应用打包的定位不同,rollup.js更专注于Javascript类库打包。
Webpack
rollup.js
Javascript
我们熟知的Vue、React等诸多知名框架或类库都是通过rollup.js进行打包的。
Vue
React
webpack我相信做前端的同学大家都用过,那么为什么有些场景还要使用rollup呢?这里我简单对webpack和rollup做一个比较:
总体来说webpack和rollup在不同场景下,都能发挥自身优势作用。webpack对于代码分割和静态资源导入有着“先天优势”,并且支持热模块替换(HMR),而rollup并不支持。
HMR
所以当开发应用时可以优先选择webpack,但是rollup对于代码的Tree-shaking和ES6模块有着算法优势上的支持,若你项目只需要打包出一个简单的bundle包,并是基于ES6模块开发的,可以考虑使用rollup。
Tree-shaking
ES6
bundle
其实webpack从2.0开始就已经支持Tree-shaking,并在使用babel-loader的情况下还可以支持es6 module的打包。实际上,rollup已经在渐渐地失去了当初的优势了。但是它并没有被抛弃,反而因其简单的API、使用方式被许多库开发者青睐,如React、Vue等,都是使用rollup作为构建工具的。
2.0
babel-loader
es6 module
API
我们先花大概十分钟左右的时间来了解下rollup的基本使用以及完成一个hello world。
hello world
首先全局安装rollup:
npm i rollup -g
接着,我们初始化一个如下所示的项目目录
├── dist # 编译结果 ├── example # HTML引用例子 │ └── index.html ├── package.json └── src # 源码 └── index.js
首先我们在src/index.js中写入如下代码:
src/index.js
console.log("柯森");
然后在命令行执行以下命令:
rollup src/index.js -f umd -o dist/bundle.js
执行命令,我们即可在dist目录下生成bundle.js文件:
dist
bundle.js
(function (factory) { typeof define === 'function' && define.amd ? define(factory) : factory(); }((function () { 'use strict'; console.log("柯森"); })));
这时,我们再在example/index.html中引入上面打包生成的bundle.js文件,打开浏览器: 如我们所预料的,控制台输出了柯森。
example/index.html
柯森
到这里,我们就用rollup打包了一个最最简单的demo。
demo
可能很多同学看到这里对于上面命令行中的参数不是很明白,我依次说明下:
-f
--format
amd
AMD
cjs
CommonJS
esm
ES
system
iife
umd
-o
其实除了这两个,还有很多其他常用的命令(这里我暂且列举剩下两个也比较常用的,完整的rollup 命令行参数):
-c
-w
rollup.config.js
使用命令行的方式,如果选项少没什么问题,但是如果添加更多的选项,这种命令行的方式就显得麻烦了。
为此,我们可以创建配置文件来囊括所需的选项
在项目中创建一个名为rollup.config.js的文件,增加如下代码:
export default { input: ["./src/index.js"], output: { file: "./dist/bundle.js", format: "umd", name: "experience", }, };
然后命令行执行:
rollup -c
打开dist/bundle.js文件,我们会发现和上面采用命令行的方式打包出来的结果是一样的。
dist/bundle.js
这里,我对配置文件的选项做下简单的说明:
input
output
output.file
output.format
output.banner
output.footer
到这里,相信你已经差不多上手rollup了。
但是,这对于真实的业务场景是远远不够的。
下面,我将介绍rollup中的几种常用的插件以及external属性、tree-shaking机制。
external
tree-shaking
resolve
在上面的入门案例中,我们打包的对象是本地的js代码和库,但实际开发中,不太可能所有的库都位于本地,我们大多会通过npm下载远程的库。
npm
与webpack和browserify这样的其他捆绑包不同,rollup不知道如何打破常规去处理这些依赖。因此我们需要添加一些配置。
browserify
首先在我们的项目中添加一个依赖the-answer,然后修改src/index.js文件:
the-answer
import answer from "the-answer"; export default function () { console.log("the answer is " + answer); }
执行npm run build。
npm run build
这里为了方便,我将原本的rollup -c -w添加到了package.json的scripts中:"build": "rollup -c -w"
rollup -c -w
package.json
scripts
"build": "rollup -c -w"
会得到以下报错: 打包后的bundle.js仍然会在Node.js中工作,但是the-answer不包含在包中。为了解决这个问题,将我们编写的源码与依赖的第三方库进行合并,rollup.js为我们提供了resolve插件。
Node.js
首先,安装resolve插件:
npm i -D @rollup/plugin-node-resolve
修改配置文件rollup.config.js:
import resolve from "@rollup/plugin-node-resolve"; export default { input: ["./src/index.js"], output: { file: "./dist/bundle.js", format: "umd", name: "experience", }, plugins: [resolve()], };
这时再次执行npm run build,可以发现报错已经没有了:
打开dist/bundle.js文件:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.experience = factory()); }(this, (function () { 'use strict'; var index = 42; function index$1 () { console.log("the answer is " + index); } return index$1; })));
打包文件bundle.js中已经包含了引用的模块。
有些场景下,虽然我们使用了resolve插件,但可能我们仍然想要某些库保持外部引用状态,这时我们就需要使用external属性,来告诉rollup.js哪些是外部的类库。
修改rollup.js的配置文件:
import resolve from "@rollup/plugin-node-resolve"; export default { input: ["./src/index.js"], output: { file: "./dist/bundle.js", format: "umd", name: "experience", }, plugins: [resolve()], external: ["the-answer"], };
重新打包,打开dist/bundle.js文件:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('the-answer')) : typeof define === 'function' && define.amd ? define(['the-answer'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.experience = factory(global.answer)); }(this, (function (answer) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var answer__default = /*#__PURE__*/_interopDefaultLegacy(answer); function index () { console.log("the answer is " + answer__default['default']); } return index; })));
这时我们看到the-answer已经是做为外部库被引入了。
commonjs
rollup.js编译源码中的模块引用默认只支持 ES6+的模块方式import/export。然而大量的npm模块是基于CommonJS模块方式,这就导致了大量 npm模块不能直接编译使用。
ES6+
import/export
因此使得rollup.js编译支持npm模块和CommonJS模块方式的插件就应运而生:@rollup/plugin-commonjs。
@rollup/plugin-commonjs
首先,安装该模块:
npm i -D @rollup/plugin-commonjs
然后修改rollup.config.js文件:
import resolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; export default { input: ["./src/index.js"], output: { file: "./dist/bundle.js", format: "umd", name: "experience", }, plugins: [resolve(), commonjs()], external: ["the-answer"], };
babel
我们在src目录下添加es6.js文件(⚠️ 这里我们使用了 es6 中的箭头函数):
src
es6.js
const a = 1; const b = 2; console.log(a, b); export default () => { return a + b; };
然后修改rollup.config.js配置文件:
import resolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; export default { input: ["./src/es6.js"], output: { file: "./dist/esBundle.js", format: "umd", name: "experience", }, plugins: [resolve(), commonjs()], external: ["the-answer"], };
执行打包,可以看到dist/esBundle.js文件内容如下:
dist/esBundle.js
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.experience = factory()); }(this, (function () { 'use strict'; const a = 1; const b = 2; console.log(a, b); var es6 = () => { return a + b; }; return es6; })));
可以看到箭头函数被保留下来,这样的代码在不支持ES6的环境下将无法运行。我们期望在rollup.js打包的过程中就能使用babel完成代码转换,因此我们需要babel插件。
首先,安装:
npm i -D @rollup/plugin-babel
同样修改配置文件rollup.config.js:
import resolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; import babel from "@rollup/plugin-babel"; export default { input: ["./src/es6.js"], output: { file: "./dist/esBundle.js", format: "umd", name: "experience", }, plugins: [resolve(), commonjs(), babel()], external: ["the-answer"], };
然后打包,发现会出现报错: 提示我们缺少@babel/core,因为@babel/core是babel的核心。我们来进行安装:
@babel/core
npm i @babel/core
再次执行打包,发现这次没有报错了,但是我们尝试打开dist/esBundle.js:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.experience = factory()); }(this, (function () { 'use strict'; const a = 1; const b = 2; console.log(a, b); var es6 = (() => { return a + b; }); return es6; })));
可以发现箭头函数仍然存在,显然这是不正确的,说明我们的babel插件没有起到作用。这是为什么呢?
原因是由于我们缺少.babelrc文件,添加该文件:
.babelrc
{ "presets": [ [ "@babel/preset-env", { "modules": false, // "useBuiltIns": "usage" } ] ] }
我们看.babelrc配置了preset env,所以先安装这个插件:
preset env
npm i @babel/preset-env
这次再次执行打包,我们打开dist/esBundle.js文件:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.experience = factory()); }(this, (function () { 'use strict'; var a = 1; var b = 2; console.log(a, b); var es6 = (function () { return a + b; }); return es6; })));
可以看到箭头函数被转换为了function,说明babel插件正常工作。
function
json
在src目录下创建json.js文件:
json.js
import json from "../package.json"; console.log(json.author);
内容很简单,就是引入package.json,然后去打印author字段。
author
修改rollup.config.js配置文件:
import resolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; import babel from "@rollup/plugin-babel"; export default { input: ["./src/json.js"], output: { file: "./dist/jsonBundle.js", format: "umd", name: "experience", }, plugins: [resolve(), commonjs(), babel()], external: ["the-answer"], };
执行打包,发现会发生如下报错: 提示我们缺少@rollup/plugin-json插件来支持json文件。
@rollup/plugin-json
来安装该插件:
npm i -D @rollup/plugin-json
同样修改下配置文件,将插件加入plugins数组即可。
plugins
然后再次打包,发现打包成功了,我们打开生成的dist/jsonBundle目录:
dist/jsonBundle
(function (factory) { typeof define === 'function' && define.amd ? define(factory) : factory(); }((function () { 'use strict'; var name = "rollup-experience"; var version = "1.0.0"; var description = ""; var main = "index.js"; var directories = { example: "example" }; var scripts = { build: "rollup -c -w", test: "echo \"Error: no test specified\" && exit 1" }; var author = "Cosen"; var license = "ISC"; var dependencies = { "@babel/core": "^7.11.6", "@babel/preset-env": "^7.11.5", "the-answer": "^1.0.0" }; var devDependencies = { "@rollup/plugin-babel": "^5.2.0", "@rollup/plugin-commonjs": "^15.0.0", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^9.0.0" }; var json = { name: name, version: version, description: description, main: main, directories: directories, scripts: scripts, author: author, license: license, dependencies: dependencies, devDependencies: devDependencies }; console.log(json.author); })));
完美!!
这里我们以最开始的src/index.js为例进行说明:
修改上述文件:
const a = 1; const b = 2; export default function () { console.log(a + b); }
执行打包。打开dist/bundle.js文件:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.experience = factory()); }(this, (function () { 'use strict'; var a = 1; var b = 2; function index () { console.log(a + b); } return index; })));
再次修改src/index.js文件:
const a = 1; const b = 2; export default function () { console.log(a); }
再次执行打包,打开打包文件:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.experience = factory()); }(this, (function () { 'use strict'; var a = 1; function index () { console.log(a); } return index; })));
发现了什么?
我们发现关于变量b的定义没有了,因为源码中并没有用到这个变量。这就是ES模块著名的tree-shaking机制,它动态地清除没有被使用过的代码,使得代码更加精简,从而可以使得我们的类库获得更快的加载速度。
b
本文大致向大家介绍了什么是rollup以及如何快速上手rollup。文中提到的这些其实只是冰山一角,rollup能玩的东西还有很多,关于更多可以去rollup 官网查询
1.如果觉得这篇文章还不错,来个分享、点赞、在看三连吧,让更多的人也看到~
2.关注公众号前端森林,定期为你推送新鲜干货好文。
3.特殊阶段,带好口罩,做好个人防护。
The text was updated successfully, but these errors were encountered:
good
Sorry, something went wrong.
No branches or pull requests
前言
项目中一直用的都是
webpack
,前一段需要开发几个类库供其他平台使用,本来打算继续用webpack
的,但感觉webpack
用来开发js
库,不仅繁琐而且打包后的文件体积也比较大。正好之前看vue
源码,知道vue
也是通过rollup
打包的。这次又是开发类库的,于是就快速上手了rollup
。本篇文章是我有了一定的项目实践后,回过来给大家分享一下如何从零快速上手
rollup
。什么是
rollup
?系统的了解
rollup
之前,我们先来简单了解下What is rollup?
关于
rollup
的介绍,官方文档已经写的很清楚了:与
Webpack
偏向于应用打包的定位不同,rollup.js
更专注于Javascript
类库打包。我们熟知的
Vue
、React
等诸多知名框架或类库都是通过rollup.js
进行打包的。为什么是
rollup
?webpack
我相信做前端的同学大家都用过,那么为什么有些场景还要使用rollup
呢?这里我简单对webpack
和rollup
做一个比较:总体来说
webpack
和rollup
在不同场景下,都能发挥自身优势作用。webpack
对于代码分割和静态资源导入有着“先天优势”,并且支持热模块替换(HMR
),而rollup
并不支持。所以当开发应用时可以优先选择
webpack
,但是rollup
对于代码的Tree-shaking
和ES6
模块有着算法优势上的支持,若你项目只需要打包出一个简单的bundle
包,并是基于ES6
模块开发的,可以考虑使用rollup
。其实
webpack
从2.0
开始就已经支持Tree-shaking
,并在使用babel-loader
的情况下还可以支持es6 module
的打包。实际上,rollup
已经在渐渐地失去了当初的优势了。但是它并没有被抛弃,反而因其简单的API
、使用方式被许多库开发者青睐,如React
、Vue
等,都是使用rollup
作为构建工具的。快速上手
我们先花大概十分钟左右的时间来了解下
rollup
的基本使用以及完成一个hello world
。安装
首先全局安装
rollup
:目录准备(hello world)
接着,我们初始化一个如下所示的项目目录
首先我们在
src/index.js
中写入如下代码:然后在命令行执行以下命令:
执行命令,我们即可在
dist
目录下生成bundle.js
文件:这时,我们再在
example/index.html
中引入上面打包生成的bundle.js
文件,打开浏览器:如我们所预料的,控制台输出了
柯森
。到这里,我们就用
rollup
打包了一个最最简单的demo
。可能很多同学看到这里对于上面命令行中的参数不是很明白,我依次说明下:
-f
。-f
参数是--format
的缩写,它表示生成代码的格式,amd
表示采用AMD
标准,cjs
为CommonJS
标准,esm
(或 es)为ES
模块标准。-f
的值可以为amd
、cjs
、system
、esm
('es’也可以)、iife
或umd
中的任何一个。-o
。-o
指定了输出的路径,这里我们将打包后的文件输出到dist
目录下的bundle.js
其实除了这两个,还有很多其他常用的命令(这里我暂且列举剩下两个也比较常用的,完整的rollup 命令行参数):
-c
。指定rollup
的配置文件。-w
。监听源文件是否有改动,如果有改动,重新打包。使用配置文件(
rollup.config.js
)使用命令行的方式,如果选项少没什么问题,但是如果添加更多的选项,这种命令行的方式就显得麻烦了。
为此,我们可以创建配置文件来囊括所需的选项
在项目中创建一个名为
rollup.config.js
的文件,增加如下代码:然后命令行执行:
打开
dist/bundle.js
文件,我们会发现和上面采用命令行的方式打包出来的结果是一样的。这里,我对配置文件的选项做下简单的说明:
input
表示入口文件的路径(老版本为 entry,已经废弃)output
表示输出文件的内容,它允许传入一个对象或一个数组,当为数组时,依次输出多个文件,它包含以下内容:output.file
:输出文件的路径(老版本为 dest,已经废弃)output.format
:输出文件的格式output.banner
:文件头部添加的内容output.footer
:文件末尾添加的内容到这里,相信你已经差不多上手
rollup
了。进阶
但是,这对于真实的业务场景是远远不够的。
下面,我将介绍
rollup
中的几种常用的插件以及external
属性、tree-shaking
机制。resolve
插件为什么要使用
resolve
插件在上面的入门案例中,我们打包的对象是本地的
js
代码和库,但实际开发中,不太可能所有的库都位于本地,我们大多会通过npm
下载远程的库。与
webpack
和browserify
这样的其他捆绑包不同,rollup
不知道如何打破常规去处理这些依赖。因此我们需要添加一些配置。resolve
插件使用首先在我们的项目中添加一个依赖
the-answer
,然后修改src/index.js
文件:执行
npm run build
。会得到以下报错:
打包后的
bundle.js
仍然会在Node.js
中工作,但是the-answer
不包含在包中。为了解决这个问题,将我们编写的源码与依赖的第三方库进行合并,rollup.js
为我们提供了resolve
插件。首先,安装
resolve
插件:修改配置文件
rollup.config.js
:这时再次执行
npm run build
,可以发现报错已经没有了:打开
dist/bundle.js
文件:打包文件
bundle.js
中已经包含了引用的模块。有些场景下,虽然我们使用了
resolve
插件,但可能我们仍然想要某些库保持外部引用状态,这时我们就需要使用external
属性,来告诉rollup.js
哪些是外部的类库。external 属性
修改
rollup.js
的配置文件:重新打包,打开
dist/bundle.js
文件:这时我们看到
the-answer
已经是做为外部库被引入了。commonjs
插件为什么需要
commonjs
插件rollup.js
编译源码中的模块引用默认只支持ES6+
的模块方式import/export
。然而大量的npm
模块是基于CommonJS
模块方式,这就导致了大量npm
模块不能直接编译使用。因此使得
rollup.js
编译支持npm
模块和CommonJS
模块方式的插件就应运而生:@rollup/plugin-commonjs
。commonjs
插件使用首先,安装该模块:
然后修改
rollup.config.js
文件:babel
插件为什么需要
babel
插件?我们在⚠️ 这里我们使用了 es6 中的箭头函数):
src
目录下添加es6.js
文件(然后修改
rollup.config.js
配置文件:执行打包,可以看到
dist/esBundle.js
文件内容如下:可以看到箭头函数被保留下来,这样的代码在不支持
ES6
的环境下将无法运行。我们期望在rollup.js
打包的过程中就能使用babel
完成代码转换,因此我们需要babel
插件。babel
插件的使用首先,安装:
同样修改配置文件
rollup.config.js
:然后打包,发现会出现报错:
提示我们缺少
@babel/core
,因为@babel/core
是babel
的核心。我们来进行安装:再次执行打包,发现这次没有报错了,但是我们尝试打开
dist/esBundle.js
:可以发现箭头函数仍然存在,显然这是不正确的,说明我们的
babel
插件没有起到作用。这是为什么呢?原因是由于我们缺少
.babelrc
文件,添加该文件:我们看
.babelrc
配置了preset env
,所以先安装这个插件:这次再次执行打包,我们打开
dist/esBundle.js
文件:可以看到箭头函数被转换为了
function
,说明babel
插件正常工作。json
插件为什么要使用
json
插件?在
src
目录下创建json.js
文件:内容很简单,就是引入
package.json
,然后去打印author
字段。修改
rollup.config.js
配置文件:执行打包,发现会发生如下报错:
提示我们缺少
@rollup/plugin-json
插件来支持json
文件。json
插件的使用来安装该插件:
同样修改下配置文件,将插件加入
plugins
数组即可。然后再次打包,发现打包成功了,我们打开生成的
dist/jsonBundle
目录:完美!!
tree-shaking
机制这里我们以最开始的
src/index.js
为例进行说明:修改上述文件:
执行打包。打开
dist/bundle.js
文件:再次修改
src/index.js
文件:再次执行打包,打开打包文件:
发现了什么?
我们发现关于变量
b
的定义没有了,因为源码中并没有用到这个变量。这就是ES
模块著名的tree-shaking
机制,它动态地清除没有被使用过的代码,使得代码更加精简,从而可以使得我们的类库获得更快的加载速度。总结
本文大致向大家介绍了什么是
rollup
以及如何快速上手rollup
。文中提到的这些其实只是冰山一角,rollup
能玩的东西还有很多,关于更多可以去rollup 官网查询❤️ 爱心三连击
1.如果觉得这篇文章还不错,来个分享、点赞、在看三连吧,让更多的人也看到~
2.关注公众号前端森林,定期为你推送新鲜干货好文。
3.特殊阶段,带好口罩,做好个人防护。
The text was updated successfully, but these errors were encountered: