2019独角兽企业重金招聘Python工程师标准>>>
深入学习rollup来进行打包
阅读目录
- 一:什么是Rollup?
- 二:如何使用Rollup来处理并打包JS文件?
- 三:设置Babel来使旧浏览器也支持ES6的代码
- 四:添加一个debug包来记录日志
- 五:添加插件来替代环境变量
- 六:添加 UglifyJS来压缩我们js的代码
- 七:监听文件变化的插件 --- rollup-watch
- 八:开启本地服务的插件 --- rollup-plugin-serve
- 九:实时刷新页面 --- rollup-plugin-livereload
- 十. 安装同时运行watcher 和 Livereload的工具
- 十一. rollup+PostCSS打包样式文件并添加 LiveReload
回到顶部
一:什么是Rollup?
rollup是一款用来es6模块打包代码的构建工具(支持css和js打包)。当我们使用ES6模块编写应用或者库时,它可以打包成一个单独文件提供浏览器和Node.js来使用。
它的优点有如下:
1. 能组合我们的脚本文件。
2. 移除未使用的代码(仅仅使用ES6语法中)。
3. 在浏览器中支持使用 Node modules。
4. 压缩文件代码使文件大小尽可能最小化。
Rollup最主要的优点是 它是基于ES2015模块的,相比于webpack或Browserify所使用的CommonJS模块更加有效率,因为Rollup使用一种叫做
tree-shaking的特性来移除模块中未使用的代码,这也就是说当我们引用一个库的时候,我们只用到一个库的某一段的代码的时候,它不会把所有的代码打包进来,而仅仅打包使用到的代码(webpack2.0+貌似也引入了tree-shaking)。
注意:Rollup只会在ES6模块中支持tree-shaking特性。目前按照CommonJS模块编写的jquery不能被支持tree-shaking.
rollup 的应用场景
现在目前流行的打包有 gulp 和 webpack,那么与前面两个对比,我觉得rollup更适合打包js库,但是对于打包一个项目的整个应用的话,我到觉得webpack更适合,比如打包一些图片,字体等资源文件的时候,webpack很适合,目前貌似没有看到rollup可以做到这些。
之所以我来研究rollup,是因为最近在看vuex的源码的时候,看到它的js库就是使用rollup来进行打包的。
回到顶部
二:如何使用Rollup来处理并打包JS文件?
2-1 安装Rollup并创建配置文件,通过如下命令安装:
进入项目根目录后,运行命令: npm install --save-dev rollup
2-2 在项目的根目录下新建一个新文件 rollup.config.js, 之后再在文件中添加如下代码:
export default { input: './src/main.js', output: { file: './dist/js/main.min.js', format: 'iife' } }
下面再来了解一下各个配置的含义:
input: rollup先执行的入口文件。
output:rollup 输出的文件。
output.format: rollup支持的多种输出格式(有amd,cjs, es, iife 和 umd, 具体看 http://www.cnblogs.com/tugenhua0707/p/8150915.html)
sourceMap —— 如果有 sourcemap 的话,那么在调试代码时会提供很大的帮助,这个选项会在生成文件中添加 sourcemap,来让事情变得更加简单。
我们在package.json代码下 添加如下脚本。
"scripts": { "build": "rollup -c" }
因此我们只要在命令行中 输入命令:npm run build 即可完成打包;
我们再看下各个文件下的代码:
src/js/a.js 代码如下:
export function a(name) { const temp = `Hello, ${name}!`; return temp; } export function b(name) { const temp = `Later, ${name}!`; return temp; }
src/js/b.js代码如下:
/** * Adds all the values in an array. * @param {Array} arr an array of numbers * @return {Number} the sum of all the array values */ const addArray = arr => { const result = arr.reduce((a, b) => a + b, 0); return result; }; export default addArray;
src/main.js代码如下:
import { a } from './js/a'; import addArray from './js/b'; const res1 = a('kongzhi'); const res2 = addArray([1, 2, 3, 4]); console.log(res1); console.log(res2);
最终会在项目的根目录下生成文件 dist/js/main.min.js, 代码如下:
(function () { 'use strict'; function a(name) { const temp = `Hello, ${name}!`; return temp; } /** * Adds all the values in an array. * @param {Array} arr an array of numbers * @return {Number} the sum of all the array values */ const addArray = arr => { const result = arr.reduce((a, b) => a + b, 0); return result; }; const res1 = a('kongzhi'); const res2 = addArray([1, 2, 3, 4]); console.log(res1); console.log(res2); }());
如上可以看到 在 src/js/a.js 下的 b函数没有被使用到,所以打包的时候没有被打包进来。
注意:在上面代码打包后,只有现代浏览器会正常工作,如果要让不支持ES2015的旧版本浏览器下也正常工作的话,我们需要添加一些插件。
回到顶部
三:设置Babel来使旧浏览器也支持ES6的代码
如上打包后的代码,我们可以在现代浏览器下运行了,但是如果我们使用老版本的浏览器的话,就会产生错误。幸运的是,Babel已经提供了支持。
我们首先需要安装一些依赖项如下命令:
npm install --save-dev babel-core babel-preset-env babel-plugin-external-helpers babel-plugin-transform-runtime babel-preset-stage-2 babel-register rollup-plugin-babel
注意:Babel preset 是一个有关Babel插件的集合,它会告诉Babel我们需要转译什么。
3.2 创建 .babelrc文件
接下来需要在项目的根目录下创建 .babelrc的新文件了,它内部添加如下JSON代码:
{ "presets": [ ["env", { "modules": false, "targets": { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] } }], "stage-2" ], "plugins": ["transform-runtime", "external-helpers"] // 配置runtime,不设置会报错 }
它会告诉Babel应该使用哪种preset来转译代码。
因此我们再更新下 rollup.config.js,我们需要Babel插件,将它添加到一个新的配置选项plugins中,他会管控一个数组形式的插件列表,代码如下:
// Rollup plugins import babel from 'rollup-plugin-babel'; export default { input: './src/main.js', output: { file: './dist/js/main.min.js', format: 'iife' }, plugins: [ babel({ exclude: 'node_modules/**' // 排除node_module下的所有文件 }) ] }
为了避免转译第三方脚本,我们需要设置一个 exclude 的配置选项来忽略掉 node_modules 目录下的所有文件。安装完成后,我们重新运行命令;然后打包后代码变成如下:
(function () { 'use strict'; function a(name) { var temp = "Hello, " + name + "!"; return temp; } /** * Adds all the values in an array. * @param {Array} arr an array of numbers * @return {Number} the sum of all the array values */ var addArray = function addArray(arr) { var result = arr.reduce(function (a, b) { return a + b; }, 0); return result; }; var res1 = a('kongzhi'); var res2 = addArray([1, 2, 3, 4]); console.log(res1); console.log(res2); }());
我们对比下代码,可以看到 addArray 的箭头函数解析成真正的函数了。 在转译运行完成后,代码也差不多一样的,只是代码已经支持
了IE9之前的浏览器了。
注意: Babel也提供了 babel-polyfill, 也可以让IE8之前的浏览器能够顺利执行。
回到顶部
四:添加一个debug包来记录日志
为了查看日志,我们将在代码中添加一个debug包来记录下日志信息。通过如下命令安装:
npm install --save debug
然后我们可以在 src/main.js中,添加一些简单的日志记录:如下代码:
import { a } from './js/a'; import addArray from './js/b'; import debug from 'debug'; const log = debug('app:log'); // Enable the logger. debug.enable('*'); log('Logging is enabled!'); const res1 = a('kongzhi'); const res2 = addArray([1, 2, 3, 4]); // Print the results on the page. const printTarget = document.getElementsByClassName('debug__output')[0]; printTarget.innerText = `sayHelloTo('Jason') => ${res1}\n\n`; printTarget.innerText += `addArray([1, 2, 3, 4]) => ${res2}`;
index.html 代码变成如下:
Learning Rollup Learning Rollup
Let’s learn how to use Rollup.
然后我们直接访问index.html后,浏览器控制台报错了,错误信息如下:
Uncaught ReferenceError: debug is not defined,然后我们可以继续查看,打包后的main.min.js的代码变为如下:
(function (debug) { 'use strict'; debug = debug && debug.hasOwnProperty('default') ? debug['default'] : debug; function a(name) { var temp = "Hello, " + name + "!"; return temp; } /** * Adds all the values in an array. * @param {Array} arr an array of numbers * @return {Number} the sum of all the array values */ var addArray = function addArray(arr) { var result = arr.reduce(function (a, b) { return a + b; }, 0); return result; }; var log = debug('app:log'); // Enable the logger. debug.enable('*'); log('Logging is enabled!'); var res1 = a('kongzhi'); var res2 = addArray([1, 2, 3, 4]); // Print the results on the page. var printTarget = document.getElementsByClassName('debug__output')[0]; printTarget.innerText = 'sayHelloTo(\'Jason\') => ' + res1 + '\n\n'; printTarget.innerText += 'addArray([1, 2, 3, 4]) => ' + res2; }(debug));
也就是说 浏览器报错是因为打包后的debug是 undefined,这是因为一般的情况下,第三方node模块并不会被Rollup正确加载。
Node模块使用的是CommonJS, 它不会被Rollup兼容因此不能直接被使用,为了解决这个问题,我们需要添加一些插件来
处理Node依赖和CommonJS模块。
为了解决上面的两个问题,我们需要在Rollup中添加如下两个插件:
1. rollup-plugin-node-resolve 该插件会允许加载在 node_modules中的第三方模块。
2. rollup-plugin-commonjs 它会将CommonJS模块转换为ES6来为Rollup获得兼容。
因此如下命令即可安装:
npm install --save-dev rollup-plugin-node-resolve rollup-plugin-commonjs
然后我们继续更新下 rollup.config.js 代码如下:
// Rollup plugins import babel from 'rollup-plugin-babel'; import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import json from 'rollup-plugin-json'; export default { input: './src/main.js', output: { file: './dist/js/main.min.js', format: 'iife' }, plugins: [ resolve({ jsnext: true, // 该属性是指定将Node包转换为ES2015模块 // main 和 browser 属性将使插件决定将那些文件应用到bundle中 main: true, // Default: true browser: true // Default: false }), commonjs(), json(), babel({ exclude: 'node_modules/**' // 排除node_modules 下的文件 }) ] }
到目前为止一切顺利,但是当我们运行index.html时候, rollup 时我们会得到一个日志信息:
在控制台如下日志信息:
app:log Logging is enabled! +0ms
index.html 页面上显示如下:
Learning Rollup Let’s learn how to use Rollup. sayHelloTo('Jason') => Hello, kongzhi! addArray([1, 2, 3, 4]) => 10
如上代码,我们看到引入了 rollup-plugin-json 插件了,该插件的作用是读取json信息的,比如我读取package.json的信息:
然后我把main.js中引入对应代码。代码如下:
import { a } from './js/a'; import addArray from './js/b'; import debug from 'debug'; // 添加json import pkg from '../package.json'; console.log( `running version ${pkg.version}` ); // 控制台输出 running version 1.0.0 const log = debug('app:log'); // Enable the logger. debug.enable('*'); log('Logging is enabled!'); const res1 = a('kongzhi'); const res2 = addArray([1, 2, 3, 4]); // Print the results on the page. const printTarget = document.getElementsByClassName('debug__output')[0]; printTarget.innerText = `sayHelloTo('Jason') => ${res1}\n\n`; printTarget.innerText += `addArray([1, 2, 3, 4]) => ${res2}`;
在控制台输出如下信息:
控制台输出 running version 1.0.0
回到顶部
五:添加插件来替代环境变量
环境变量能为我们的开发流程提供很大的帮助,我们可以通过它来执行关闭或开启日志,注入开发环境脚本等功能。
因此我们可以在main.js中添加基础配置的ENV。让我们添加一个环境变量来使我们的日志脚本只在非 production环境下才会执行
。如下main.js代码:
import { a } from './js/a'; import addArray from './js/b'; import debug from 'debug'; // 添加json import pkg from '../package.json'; console.log( `running version ${pkg.version}` ); // 控制台输出 running version 1.0.0 const log = debug('app:log'); // 如果是正式环境的话,不输出日志信息 if (ENV !== 'production') { // Enable the logger. debug.enable('*'); log('Logging is enabled!'); } else { debug.disable(); } const res1 = a('kongzhi'); const res2 = addArray([1, 2, 3, 4]); // Print the results on the page. const printTarget = document.getElementsByClassName('debug__output')[0]; printTarget.innerText = `sayHelloTo('Jason') => ${res1}\n\n`; printTarget.innerText += `addArray([1, 2, 3, 4]) => ${res2}`;
然后打包完成后,在浏览器查看 发现报错了,如下错误信息:
Uncaught ReferenceError: ENV is not defined
这也很正常,因为我们并没有定义它,现在我们还需要一个插件来将我们的环境变量用到bundle中。
5-1 先安装 rollup-plugin-replcae,该插件是一个用来查找和替换的工作,我们只需要找到目前的环境变量并且使用实际
的值替代就可以了。先安装如下:
npm install --save-dev rollup-plugin-replace
然后我们再来更新一下 rollup.config.js, 配置是我们可以添加一个 key:value 的配对表,key值是准备被替换的键,而value是将要被替换的值。
// Rollup plugins import babel from 'rollup-plugin-babel'; import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import json from 'rollup-plugin-json'; import replace from 'rollup-plugin-replace'; export default { input: './src/main.js', output: { file: './dist/js/main.min.js', format: 'iife' }, plugins: [ resolve({ jsnext: true, // 该属性是指定将Node包转换为ES2015模块 // main 和 browser 属性将使插件决定将那些文件应用到bundle中 main: true, // Default: true browser: true // Default: false }), commonjs(), json(), babel({ exclude: 'node_modules/**' // 排除node_modules 下的文件 }), replace({ ENV: JSON.stringify(process.env.NODE_ENV || 'development') }) ] }
当我们现在运行 npm run build 的时候还是有日志信息的,因为默认的环境就是 development, 但是当我们在命令
行中使用如下命令:`NODE_ENV=production ./node_modules/.bin/rollup -c`(mac系统下的命令), 然后打包
后,刷新浏览器 就不会有日志记录信息了。
注意:在winodw环境下,运行如下命令: SET NODE_ENV=production ./node_modules/.bin/rollup -c
回到顶部
六:添加 UglifyJS来压缩我们js的代码
安装插件 rollup-plugin-uglify
命令如下安装:
npm install --save-dev rollup-plugin-uglify
再在 rollup.config.js 配置代码,为了在开发中使代码更具可读性,我们只在生产环境压缩代码:
rollup.config.js配置代码如下:
// Rollup plugins import babel from 'rollup-plugin-babel'; import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import json from 'rollup-plugin-json'; import replace from 'rollup-plugin-replace'; import uglify from 'rollup-plugin-uglify'; export default { input: './src/main.js', output: { file: './dist/js/main.min.js', format: 'iife' }, plugins: [ resolve({ jsnext: true, // 该属性是指定将Node包转换为ES2015模块 // main 和 browser 属性将使插件决定将那些文件应用到bundle中 main: true, // Default: true browser: true // Default: false }), commonjs(), json(), babel({ exclude: 'node_modules/**' // 排除node_modules 下的文件 }), replace({ ENV: JSON.stringify(process.env.NODE_ENV || 'development') }), (process.env.NODE_ENV === 'production' && uglify()) ] }
当我们在mac系统下运行命令 `NODE_ENV=production ./node_modules/.bin/rollup -c` 后,代码被压缩了,当我们运行
npm run build 的时候,代码未被压缩。
回到顶部
七:监听文件变化的插件 --- rollup-watch
如下安装命令:
npm install --save-dev rollup-watch
然后在package.json 中设置 scripts属性即可:
"scripts": { "dev": "rollup -c -w", "build": "rollup -c" }
当我们在 src/main.js 代码下 加入一句代码后 : console.log(1122); 然后在浏览器下刷新下即可在控制台可以看到打印输出 1122这样的就可以监听到了。不需要重新打包即可。
回到顶部
八:开启本地服务的插件 --- rollup-plugin-serve
安装命令如下:
npm install --save-dev rollup-plugin-serve
在rollup.config.js 配置代码如下:
// Rollup plugins import babel from 'rollup-plugin-babel'; import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import json from 'rollup-plugin-json'; import replace from 'rollup-plugin-replace'; import uglify from 'rollup-plugin-uglify'; import serve from 'rollup-plugin-serve'; export default { input: './src/main.js', output: { file: './dist/js/main.min.js', format: 'iife' }, plugins: [ resolve({ jsnext: true, // 该属性是指定将Node包转换为ES2015模块 // main 和 browser 属性将使插件决定将那些文件应用到bundle中 main: true, // Default: true browser: true // Default: false }), commonjs(), json(), babel({ exclude: 'node_modules/**' // 排除node_modules 下的文件 }), replace({ ENV: JSON.stringify(process.env.NODE_ENV || 'development') }), (process.env.NODE_ENV === 'production' && uglify()), serve({ open: true, // 是否打开浏览器 contentBase: './', // 入口html的文件位置 historyApiFallback: true, // Set to true to return index.html instead of 404 host: 'localhost', port: 10001 }) ] }
然后重启命令 npm run build 就可以会自动打开 http://localhost:10001/ 页面了。
注意: 这边port配置的端口号是五位数,不是四位数。
回到顶部
九:实时刷新页面 --- rollup-plugin-livereload
命令安装如下:
npm install --save-dev rollup-plugin-livereload
注入LiveReload脚本
在LiveReload工作前,需要向页面中注入一段脚本用于和LiveReload的服务器建立连接。
在src/main.js 中加入如下一段代码:
// Enable LiveReload document.write( '