Rollup也是一款ESModule打包器,可以将项目中的细小模块打包成整块代码,使得划分的模块可以更好的运行在浏览器环境或者是Nodejs环境。Rollup与Webpack作用非常类似,不过Rollup更为小巧。webpack结合插件可以完成前端工程化的绝大多数工作,而Rollup仅仅是一款ESM打包器,没有其他功能,例如Rollup中并不支持类似HMR这种高级特性。Rollup并不是要与Webpack全面竞争,而是提供一个充分利用ESM各项特性的高效打包器。
一、rollup使用
./src/message.js
export default {
hi: 'Hey Guys, I am jal '
}
./src/logger.js
export const log = msg => {
console.log('---Info----')
console.log(msg)
console.log('-----------')
}
export const error = msg => {
console.error('---Error-----')
console.error(mes)
console.error('-------------')
}
./src/index.js
import {log} from './logger'
import messages from './message'
const msg = messages.hi
log(msg)
安装Rollup:yarn add rollup --dev
运行:yarn rollup ./src/index.js --format iife --file dist/bundle.js
./dist/bundle.js
(function () {
'use strict';
const log = msg => {
console.log('---Info----');
console.log(msg);
console.log('-----------');
};
var messages = {
hi: 'Hey Guys, I am jal '
};
const msg = messages.hi;
log(msg);
}());
Rollup默认会开启TreeShaking优化输出结果。
配置文件:rollup.config.js
export default {
input: './src/index.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
}
}
运行:yarn rollup --config
, 指定配置文件:yarn rollup --config rollup.config.js
二、rollup插件
Rollup自身的功能就是对ESM进行合并打包,如果需要更高级的功能,如加载其他类型资源模块、导入CommonJS模块、编译ES新特性等,Rollup支持使用插件的方式扩展实现,插件是Rollup唯一的扩展方式。
通过导入json文件学习如何使用Rollup插件。
安装插件rollup-plugin-json, 运行:yarn add rollup-plugin-json —dev
Rollup.config.js
import json from 'rollup-plugin-json'
export default {
input: './src/index.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
json()
]
}
./src/index.js
import {log} from './logger'
import messages from './message'
import {name, version} from '../package.json'
const msg = messages.hi
log(msg)
log(name)
log(version)
./dist/bundle.js
(function () {
'use strict';
const log = msg => {
console.log('---Info----');
console.log(msg);
console.log('-----------');
};
var messages = {
hi: 'Hey Guys, I am jal '
};
var name = "Rollup-test";
var version = "1.0.0";
const msg = messages.hi;
log(msg);
log(name);
log(version);
}());
json中用到的属性被打包进来了,没用到的属性被TreeShaking移除掉了。
三、rollup 加载npm依赖
Rollup不能像webpack那样通过模块名称加载npm模块,为了抹平差异,Rollup官方提供了一个插件rollup-plugin-node-resolve,通过这个插件,就可以在代码中使用模块名称导入模块。
安装插件:yarn add rollup-plugin-node-resolve —dev
Rollup.config.js
import json from 'rollup-plugin-json'
import resolve from 'rollup-plugin-node-resolve'
export default {
input: './src/index.js',
output: {
file: 'dist/bundle.js',
format: 'iife'
},
plugins: [
json(),
resolve()
]
}
./src/index.js
import _ from 'lodash-es' // lodash模块的ESM版本
import {log} from './logger'
import messages from './message'
import {name, version} from '../package.json'
const msg = messages.hi
log(msg)
log(name)
log(version)
log(_.camelCase('hello world'))
四、Rollup加载CommonJS模块
安装插件: yarn add rollup-plugin-commonjs
Rollup.config.js
import json from 'rollup-plugin-json'
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: 'iife'
},
plugins: [
json(),
resolve(),
commonjs()
]
}
./src/index.js
import _ from 'lodash-es' // lodash模块的ESM版本
import {log} from './logger'
import messages from './message'
import {name, version} from '../package.json'
import cjs from './cjs.module'
const msg = messages.hi
log(msg)
log(name)
log(version)
log(_.camelCase('hello world'))
log(cjs)
./dist/bundle.js
// ...
var cjs_module = {
foo: 'bor'
};
// ...
log(cjs_module);
// ...
五、Rollup代码拆分 : 动态导入
使用动态导入的方式实现模块的按需加载,Rollup内部会自动去处理代码的拆分,也就是分包。
代码拆分的话要改成amd格式输出打包结果
Rollup.config.js
import json from 'rollup-plugin-json'
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: 'iife',
dir: 'dist',
format: 'amd'
},
plugins: [
json(),
resolve(),
commonjs()
]
}
./src/index.js
import('./logger').then(({ log }) => {
log('code splitting~')
})
六、Rollup多入口打包
rollup.config.js
import json from 'rollup-plugin-json'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
export default {
// input: './src/index.js',
// input: ['src/index.js', 'src/album.js'], // 多入口打包
input: { // 这种写法也可以进行多入口打包
foo: 'src/index.js',
bar: 'src/album.js'
},
output: {
// file: 'dist/bundle.js',
// format: 'iife',
dir: 'dist', // 动态导入时会分包成多文件
format: 'amd' // 动态导入不支持iife
},
plugins: [
json(),
resolve(),
commonjs()
]
}
注意此时生成的js文件就要以AMD标准的require方式引入
<script src="https://unpkg.com/requirejs@2.3.6/require.js" data-main="foo.js"></script>
Rollup、Webpack选用原则
(1) Rollup优势
- 输出结果更加扁平,执行效率更高
- 自动移除未引用的代码
- 打包结果依然完全可读
(2) Rollup缺点
- 加载非ESM的第三方模块比较复杂
- 模块最终都会被打包到一个函数中,无法实现HMR
- 浏览器环境中,代码拆分功能依赖AMD库
- 如果我们正在开发应用程序,需要引入大量的第三方库,代码量又大,需要分包打包,Rollup的作用则会比较欠缺。
如果我们正在开发一个框架或者类库,Rollup的这些优点则非常有必要,缺点则可以忽略。所以大多数知名框架/库都在使用Rollup作为模块打包器。
总结:Webpack大而全,Rollup小而美。
选择标准:
- 开发应用程序选择Webpack
- 开发框架/库使用Rollup
Parcel
安装Parcel:yarn add parcel-bundler --dev
./src/index.html Parcel中的入口文件是HTML文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Parcel Test</title>
</head>
<body>
<script src="./main.js"></script>
</body>
</html>
./src/main.js
// import $ from 'jquery' // 自动安装依赖
import foo from './foo'
import './style.css'
import img from './1.png'
foo.bar()
// 动态导入,自动拆分模块
import('jquery').then($=>{
$(document.body).append('<h1>Hello</h1>')
$(document.body).append(`<img src="${img}" />`)
})
if(module.hot) {
module.hot.accept(() => {
console.log('hmr') // 模块热替换
})
}
./src/foo.js
export default {
bar: () => {
console.log('foo jal111 ..')
}
}
./src/style.css
body {
background-color: pink;
}
./src/1.png
执行命令:yarn parcel src/index.html 会自动启动一个http服务,并且监听文件的变化,自动开启了模块热替换功能,依赖文件也是自动安装,整个过程都是零配置。
如何以生产模式进行打包:yarn parcel build src/index.html
对于相同体量的项目进行打包,Parcel会比Webpack快很多,因为在Parcel内部使用的是多进程同时去工作,充分发挥了多核CPU的性能,而Webpack中可以使用happypack插件实现这一点。
Parcel首个版本发布于2017年,当时Webpack使用上过于繁琐。Parcel真正意义上实现了完全零配置,而且Parcel构建速度更快。
而现在大多数项目还是使用Webpack作为打包器,可能是因为Webpack有更好的生态、Webpack越来越好用。