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.hilog(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.hilog(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.hilog(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.hilog(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越来越好用。
