rollup是一個js打包器,用來將很細碎的js編譯打包成大的複雜的東西,像是一個庫或者一個應用。其使用了ES6自帶的新標準來格式化和打包js代碼,而不是原先的Commonjs或者AMD這類解決方案。ES6模塊可以使你輕鬆的無縫的組合你所喜歡庫中的獨立函數(靜態函數)。這使得最後可以實現本地化,rollup現在實現了這些。java
使用npm install --global rollup
命令下載安裝。rollup既能夠經過一個配置文件使用命令行接口來調用,也能夠他本身的Javascript API
使用。運行rollup --help
查看可用的命令和參數。starter project template
有一些經常使用設置的說明,若是須要更詳細的說明,點擊user guide
。node
這些名設定你的應用的入口是main.js
,而且但願這些導入最後打包成一個bundle.js
命名的文件。webpack
瀏覽器環境git
# compile to a <script> containing a self-executing function # 編譯到一個<script>元素包含的獨立的函數。 $ rollup main.js --format iife --output bundle.js
Node.js環境es6
# compile to a CommonJS module # 變異成一個CommonJS標準的模塊 $ rollup main.js --format cjs --output bundle.js
瀏覽器和node.js兼容的環境github
# UMD format requires a bundle name $ rollup main.js --format umd --name "myBundle" --output bundle.js
把項目分紅各個小的部分來開發軟件一般活容易些。由於常常須要去掉代碼不指望的行爲,也可以很大程度上下降解決問題的複雜程度,並且能夠只在項目的第一個位置寫一些小的項目而不是 isn't necessarily the answer
。不幸的是,JavaScript自己的語言設計沒有這類功能。web
爲了可以實現ES6模塊功能,rollup會靜態地分析你所引入的模塊,而後去掉沒有真正用到的部分。這會幫助你至引入那些須要的東西,而且減小項目的體積。ajax
例如,若是使用CommonJS.整個的工具和庫都會被導入。typescript
// import the entire utils object with CommonJS // 使用CommonJS整個的導入utils var utils = require( 'utils' ); var query = 'rollup'; // use the ajax method of the utils object // 僅使用utils中的ajax方法 utils.ajax( 'https://api.example.com?search=' + query ).then( handleResponse );
可是若是使用ES6模塊系統。替代整個引入utils模塊,而是僅僅引入咱們所須要的ajax
函數。npm
// import the ajax function with an ES6 import statement //使用es6語句引入ajax函數 import { ajax } from 'utils'; var query = 'rollup'; // call the ajax function // 調用ajax函數 ajax( 'https://api.example.com?search=' + query ).then( handleResponse );
由於rollup只包含最低所需,所以它打包的應用體積更小,更快速,而且使得應用和庫之間解耦更鬆散。
由於這種方法是創建在import
和export
語句上,所以其效率極高,運行時自動縮減體積,探測打包文件中不須要的變量。
rollup 可以經過插件導入CommondJS模塊。
爲了保證你的ES6模塊可以立刻被CommonJS的工具使用,例如在Node或者webpack中,你可使用rollup來轉化成UMD或者CommonJS格式風格。而後指定編譯的版本在一個有mian
屬性的package.json
文件中。若是你的package.json文件也有module
域(屬性),es6敏感的工具,如rollup以及webpack2將會直接導入ES6模塊版本。、
step-by-step tutorial video series, with accompanying written walkthrough
miscellaneous issues in thewiki
.
開始以前,你的電腦應該已經安裝了node.js,所以你可以使用npm,此外你也須要知道怎麼使用命令行工具。
使用rollup最簡單的方法就是經過命令行接口。如今咱們要全局安裝rollup,在命令行輸入以下命令。(稍後咱們將學習如何本地安裝到你的項目中,那麼你的打包將更加愛便捷,暫時先不要管這麼多)。
npm install rollup --global # or `npm i rollup -g` for short
如今你可使用rollup
,命令了。
由於沒有傳遞參數,因此rollup只是打印出使用說明。這根rollup --help
或者rollup -h
的結果是同樣的。
如今,來建立一個簡單的項目。
mkdir -p my-rollup-project/src cd my-rollup-project
首先,咱們須要一個入口點entry point
,粘貼下面的代碼到main.js
文件中。
// src/main.js import foo from './foo.js'; export default function () { console.log(foo); }
而後在建立一個foo.js
文件,就是咱們導入點導入的文件。
// src/foo.js export default 'hello world!';
如今咱們來準備生成一個bundle。
rolup src/main.js --format cjs
--format
選項制定咱們要打包成什麼格式。在這個例子中是CommonJS(可以在Node.js運行)。由於咱們沒有制定輸出的文件,所以將會打印到命令行。(標準輸出stdout)。
'use strict'; var foo = 'hello world!'; var main = function () { console.log(foo); }; module.exports = main;
你可使用以下方法保存編譯出來的bundle。
rollup src/main.js --format cjs --output bundle.js # or `rollup main.js -f cjs -o bundle.js`
(你也可使用rollup src/main.js > bundle.js
,可是下面你會明白,這種方式在你想要生成map文件時缺少靈活性。)
運行這個代碼
node > var myBundle = require('./bundle.js'); > myBundle(); 'hello world!'
祝賀,你已經使用rollup建立了第一個bundle。
目前爲止,都還不錯,可是當咱們開始添加更多的設置時,這就變成了使人討厭的在命令行輸入(不少)。爲了保存咱們本身經常使用的設置,咱們能夠建立一個配置文件,裏面保存咱們須要的設置。使用js寫配置文件比使用命令行方便多了。
在根目錄建立一個配置文件,命名rollup.config.js
,而後添加以下代碼。
//rollup.config.js export default { entry:'src/main.js', format:'cjs', dest:'bundle.js'//等於--output }
使用 --config or -c flag:來使用該文件。
rm bundle.js//而後檢查該命令是否有效。 rollup -c
你可使用相應的命令行命令來覆蓋設置文件中的行爲。
rollup -c -o bundle-2.js
(注意:rollup是本身運行配置文件,所以咱們可使用export default
語法。語法沒有被bable編譯,因此你只能使用當前node版本所支持的es2015語法。)
固然,若是你喜歡你能夠制定不用的設置文件。
rollup --config rollup.config.dev.js rollup --confog rollup.config.prod.js
不少javaScript項目有一個慣例:在命令行執行npm run build
就可執行建立——不管是什麼平臺的系統。這個頗有用,由於若是有人想對你的項目有所貢獻(即分支之類的),那麼他就能夠直接去關注源碼便可而不用分心去了解用了什麼依賴,怎麼組合等(如此這樣的有,rollup,webpack,gulp或者其餘)。他們甚至都不用全局安裝,就像咱們在學習第一部分所作的那樣。
設置你本身的npm run build
是很好且簡單的。
一個package.json文件保存着你的項目的一些重要的信息,包括名字,版本,受權以及以來。(事實上,若是沒有package.json文件你不能把你的項目發表到npm庫中——若是你是建立一個應用而非lib庫,你仍須要一個package.json文件)。
建立package.json最簡單的方法是在你項目所在的目錄的命令行運行npm init
名來,並跟着提示一步一步來即可。
打開你的package.json文件而且在scripts
屬性下添加build
入口:
{ ... "scripts":{ "test":"echo \" Error:no test specified\"&& exit 1", "build":"rollup -c" } }
(這個前提是假設你已經設置了rollup.config.js
文件在你的項目目錄中)
到目前爲止咱們一直使用的是全局安裝rollup。使用本地安裝rollup是一個更好的選擇,由於任何複製了你項目的人制藥運行了npm install
指令,就會獲得一個獨立兼容(compatible version)版本。
npm install --save-dev rollup #or `npm i -D rollup`
以後注意package.json中的devDependencies
屬性將會存在。
{ ..., "devDependencies": { "rollup": "^0.43.0" }, ... }
全部你的npm run
將會尋找本地版原本運行,若是rollup在本地存在的話。
試下下面的命令。
npm run build
npm run dev
實現監控試試編譯經過安裝rollup watch
你能夠建立一個命令,在源碼出現變化是實時編譯。
npm install --save-dev rollup-watch
package.json
{ ..., "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "rollup -c", "dev": "rollup -c -w" }, ... }
命令rollup -c -w
(rollup --config --watch
縮寫)會以監視模式運行rollup。
目前爲止,咱們經過入口文件建立了個一簡單的bundle,而且使用相對路徑導入了一個模塊。隨着須要打包更復雜的bundle,你常常須要一些靈活的特性——導入從npm下載的模塊,經過babel編譯模塊,使用json等。
爲了應對這些咱們使用插件,這些插件會改變rollup在編譯時的一些行爲。在the rollup wiki中能夠找到目前維護的一些插件。
在這個教程裏咱們將使用rollup-plugin-json
插件,它可以使rollup導入json文件裏的數據。
安裝rollup-plugin-json
做爲開發時依賴(development dependency)。
npm install --save-dev rollup-plugin-json
(咱們使用--save-der而不是--save是由於個人代碼在運行時不是真正的以來這個插件——只是在咱們編譯bundle時依賴而已。)
修改你的src/main.js
文件,讓他導入package.json而不是src/foo.js
。
import { version } from '../package.json'; export default function () { console.log('version ' + version); }
運行npm run build
,結果回事以下的樣子:
'use strict'; var version = "1.0.0"; var main = function () { console.log('version ' + version); }; module.exports = main;
(注意:只有咱們真正所須要的數據纔會被導入——version,其餘的name,devDependencies等package.json中的屬性將會被忽略,這就是tree-shaking的做用。)
在某種狀況下,你的項目須要下載npm的第三方模塊到你的node_modules
文件夾中。跟其餘的如webpack,Browserfy不一樣,rollup不知道out of box
,怎麼處理這些依賴,咱們須要添加一些設置。
下載一個the answer
依賴,它導出life,universe,everything問題的答案,
npm install --save the-answer # or `npm i -S the-answer`
注意:此處咱們使用的是--save
,所以它被保存到package.json的dependencies
屬性中。
若是咱們更新src/main.js
文件。。。
import answer from 'the-answer'; export default function () { console.log('the answer is ' + answer); }
而後運行rollup
npm run build
咱們會看到以下的警告
⚠️ 'the-answer' is imported by src/main.js, but could not be resolved – treating it as an external dependency.
導出來的bundle.js
仍然可以在Node.js下運行,由於import
聲明被轉化成CommonJS風格的require
語句,可是the-answer
沒有放到bundle中,所以咱們須要一個插件。
rollup-plugin-node-resolve插件教會rollup怎麼去找到擴展的模塊。安裝。
npm install --save-dev rollup-plugin-node-resolve
這時運行下npm run build
將不會有錯誤拋出,bundle包含導入的組件。
有些庫導出的是es6模塊,因此你可import
——the-answer
就是這種。然而npm的大多數第三方庫是CommonJS風格的模塊。在其發生改變以前,咱們須要轉換CommonJS爲ES2015的模塊,而後再用rollup處理。
這正是rollup-plugin-commonjs
的功能所在。
注意rollup-plugin-commonjs
必須在其餘的插件轉化你的模塊以前運行——這是爲了防止其餘插件打斷對CommonJS的探測。
假如你正在建立一個庫而且有一個同級依賴(即你的庫所須要的依賴而不是開發依賴),例如React或者Loadash等。若是你像咱們上面所講的那樣引入其中,你的bundle將會包含他們所有。
import answer from 'the-answer'; import _ from 'lodash';
你能夠優雅地處理引入的模塊以及bundle。這個李子中,咱們把lodash做爲模塊,可是the-answer不是。
// rollup.config.js import resolve from 'rollup-plugin-node-resolve'; export default { entry: 'src/main.js', format: 'cjs', plugins: [resolve({ // pass custom options to the resolve plugin customResolveOptions: { moduleDirectory: 'node_modules' } })], // indicate which modules should be treated as external external: ['lodash'], dest: 'bundle.js' };
如今看下,lodash
會被視做外部,而不是打包到你的lib裏面。external
關鍵字接受一個模塊的數組或者一個函數,這個函數的參數是模塊的名字,若是這個模塊應該不被打包到其中,那麼返回true。
export default { // ... external: id => /lodash/.test(id) }
若是你是用babel-plugin-lodash
插件來cherry-pick
lodash模塊的話,也許會用這個功能。在這個示例中,Babel將會覆蓋你的import語句。
import _merge from 'lodash/merge'
external
數組不會處理通配符,所以import將僅僅做爲不打包而已。
不少開發者會在他們的項目中使用Babel
,所以他們可使用一些超前的es6特性,這樣可以在瀏覽器和node環境中使用。
同時使用rollup和Babel的最簡單的方法是使用rollup-plugin-babel
插件。安裝:
npm i -D rollup-plugin-babel
在rollup.config.js
中配置。
// rollup.config.js import resolve from 'rollup-plugin-node-resolve'; import babel from 'rollup-plugin-babel'; export default { entry: 'src/main.js', format: 'cjs', plugins: [ resolve(), babel({ exclude: 'node_modules/**' // only transpile our source code }) ], dest: 'bundle.js' };
在babel可以真正的編譯源碼以前,你須要一些設置,建立一個新文件src/.babelrc
:
{ "presets": [ ["latest", { "es2015": { "modules": false } }] ], "plugins": ["external-helpers"] }
在這一步有一些東西跟往常不太同樣。首先咱們設置modules:false
,不然Babel將會在rollup轉化前轉化咱們的模塊爲CommonJS風格,這樣就沒法實現rollup的目的(tree shaking)。
其次,咱們使用了external-helpers
插件,它使rollup在bundle的頭部添加一次'helper',而不是在每一個使用模塊的地方包含他們(這是默認行爲)。
第三咱們把.babelrc
放在了src文件夾裏,而不是項目的跟目錄,若是咱們售後須要它,這個容許咱們有不一樣的.babelrc
文件對應不一樣的需求,例如測試。(針對不一樣的需求設置不一樣的配置是個好的方法)
如今,在運行rollup以前,咱們須要安裝latest
預設以及external-helers
插件。
npm i -D babel-preset-latest babel-plugin-external-helpers
如今運行rollup生成不打了,此時可使用es2015特性了。首先更新下src/main.js
的內容。
import answer from 'the-answer'; export default () => { console.log(`the answer is ${answer}`); }
使用npm run build
運行rollup,而後查看bundle。
'use strict'; var index = 42; var main = (function () { console.log('the answer is ' + index); });
映射能夠經過添加--sourcemap
命令行flag實現,也能夠經過在配置文件中設置sourceMap:true
屬性實現。
什麼是‘tree shaking’?
Tree-shaking是活的代碼放入——code inclusion,是一種只填加那些使用了的代碼的處理,相似於無用代碼剔除,而後提升效率。閱讀了解更多:Tree-shaking vs Dead-Code-Elimination
爲何原生的ES2015的模塊系統更優於AMD和CommonJS模塊標準?
ES2015是官方標準,很快會被瀏覽器以及Node.js所實現。它們容許靜態分析實現相似tree-shaking這樣的效果,而且擁有更高級的特性,如循環引用,實時綁定(live-binding)等。
誰設計了rollup logo?看起來可耐。Julian Lioyd
coming soon...
rollup 返回的是一個Promises,因此gulp能夠很容易的集成。
語法跟配置文件很想,可是屬性分散到兩個不一樣的設置裏。
構造bundle,而後導出到目標output。
var gulp = require('gulp') rollup = require('rollup') rollupTypescript = require('rollup-plugin-typescript') ; gulp.task('build',function(){ return rollup.rollup({ entry:"./src/main.js", plugins:[rollupTypescript()], }).then(function(bundle){ bundle.write({ format:'umd', moduleName:'library', dest:'./dest/library.js', sourceMap:true }); }) });