深入學習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 程式碼變成如下:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"> <title>Learning Rollup</title> </head> <body> <h1>Learning Rollup</h1> <p> Let’s learn how to use <a href="http://rollupjs.org/">Rollup</a>. </p> <!-- JS-generated output will be added here. --> <pre class="debug"><code class="debug__output"></code></pre> <!-- This is the bundle generated by rollup.js --> <script src="./dist/js/main.min.js"></script> </body> </html>
然後我們直接訪問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( '<script src="http://' + (location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1"></' + 'script>' );
src/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!'); // Enable LiveReload document.write( '<script src="http://' + (location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1"></' + 'script>' ); } else { debug.disable(); } const res1 = a('kongzhi'); const res2 = addArray([1, 2, 3, 4]); console.log(1122) // 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}`;
執行 LiveReload
LiveReload安裝好並且指令碼注入到文件中後,我們可以執行它去監聽build目錄:
如下命令:
./node_modules/.bin/livereload 'build/'
執行完成後 發現報錯了 Error: listen EADDRINUSE :::35729;通過百度才發現埠被佔用了,需要換埠,因此我直接把這個程式殺掉不就可以了,
首先我們先使用如下命令來檢視下程式:
lsof -n -i4TCP:35729
看到資訊如下:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME node 1452 tugenhua 15u IPv6 0xb0e27d409cc55a1b 0t0 TCP *:35729 (LISTEN)
執行如下命令殺掉:
kill -9 1452
再在命令列輸入 ./node_modules/.bin/livereload 'src/' 即可看到如下:
$ ./node_modules/.bin/livereload 'src/'
Starting LiveReload v0.6.3 for /Users/tugenhua/個人demo/vue1204/rollup-build/src on port 35729.
注意:./node_modules/.bin/livereload 'src/' 這句程式碼的含義是 監聽src資料夾的檔案,因此index.html內會
監聽到,我們可以開啟 src/index.html後,然後在index.html修改內容後,儲存一下就可以看到頁面會自動重新整理內容了。
如上雖然改變 src/index.html的內容後會自動重新整理頁面,但是感覺每次 都需要輸入 ./node_modules/.bin/livereload 'src/' 這麼一段命令,有點麻煩,因此我們可以在 package.json 指令碼中來簡化這個過程,在package.json下scripts加上如下程式碼:
"scripts": { "dev": "rollup -c -w", "build": "rollup -c", "reload": "livereload 'src/'" },
當我們在命令列中 執行 npm run reload 也可以監聽到了。但是我們監聽不到 src/js 或 src/css 下的檔案的變化,
因為它不會自動打包,而只是監聽src下的檔案變化而已。但是我們又不能同時開啟 watcher 和 Livereload,會報錯埠被佔用的情況。
因此我們需要看第10條來解決這個問題哦;
十. 安裝同時執行watcher 和 Livereload的工具
為了能同時執行 Rollup和LiveReload, 我們需要使用一個叫做 npm-run-all 的工具。它的含義是一個終端可以執行多個任務。
安裝命令如下:
npm install --save-dev npm-run-all
然後我們要在package.json中再加入一條呼叫npm-run-all的指令碼。在scripts程式碼塊內,新增如下內容:
"scripts": { "dev": "rollup -c -w", "build": "rollup -c", "reload": "livereload 'src/'", "watch": "npm-run-all --parallel dev" },
watch 就是新增的。因此我們可以在終端執行 npm run watch命令了,然後重新整理瀏覽器(http://localhost:10002/src/index.html),改變一下js或者css,瀏覽器會自動載入更新後的程式碼了。
十一. rollup+PostCSS打包樣式檔案並新增 LiveReload
1. 在main.js中載入樣式: 在main.js 中加入如下程式碼:
// Import styles (automatically injected into <head>). import './css/index.css'; 所有的程式碼如下: import './css/index.css'; 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!'); // Enable LiveReload document.write( '<script src="http://' + (location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1"></' + 'script>' ); } else { debug.disable(); } const res1 = a('kongzhi222'); const res2 = addArray([1, 2, 3, 4]); console.log(11222211) // 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}`;
2. 安裝PostCss外掛
首先需要安裝Rollup版本的PostCss外掛,使用命令如下安裝:
npm install --save-dev rollup-plugin-postcss
然後 新增外掛到 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'; import livereload from 'rollup-plugin-livereload'; // 新增的postcss import postcss from 'rollup-plugin-postcss'; export default { input: './src/main.js', output: { file: './dist/js/main.min.js', format: 'iife' }, plugins: [ // 新增的postcss postcss({ extensions: ['.css'] }), 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: 10002 }), livereload() ] }
執行npm run build 後,可以看到生成的 dist/js/main.min.js 中的程式碼,在檔案開頭幾行,可以看到一個名叫__$styleInject()的新函式;
程式碼如下:
function __$styleInject(css, returnValue) { if (typeof document === 'undefined') { return returnValue; } css = css || ''; var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; head.appendChild(style); if (style.styleSheet){ style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } return returnValue; }
這個函式建立了一個<style>元素並設定樣式,然後新增到文件的<head>標籤中。
但現在這些樣式並沒有真正地被處理;PostCSS只是直接地傳輸了我們的樣式。讓我們新增一些需要的PostCSS外掛,使得樣式能在目標瀏覽器上工作。
3. 安裝必要的 PostCSS外掛
下面需要安裝四個外掛,如下外掛:
postcss-simple-vars 可以使用Sass風格的變數(e.g. $myColor: #fff;,color: $myColor;)而不是冗長的CSS語法(e.g. :root {--myColor: #fff},color: var(--myColor))。
postcss-nested 允許使用巢狀規則。實際上我不用它寫巢狀規則;
postcss-cssnext 這個外掛集使得大多數現代CSS語法(通過最新的CSS標準)可用,編譯後甚至可以在不支援新特性的舊瀏覽器中工作。
cssnano — 壓縮,減小輸出CSS檔案大小。相當於JavaScript中對應的UglifyJS。
使用如下命令安裝即可:
npm install --save-dev postcss-simple-vars postcss-nested postcss-cssnext cssnano
我們再來更下 rollup.config.js
現在我們可以在rollup.config.js 中引入 postcss外掛了,在配置物件的plugins屬性上新增一個postcss。
如下程式碼:
// 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'; import livereload from 'rollup-plugin-livereload'; // 新增 rollup-plugin-postcss 外掛 import postcss from 'rollup-plugin-postcss'; // 新增 postcss plugins import simplevars from 'postcss-simple-vars'; import nested from 'postcss-nested'; import cssnext from 'postcss-cssnext'; import cssnano from 'cssnano'; export default { input: './src/main.js', output: { file: './dist/js/main.min.js', format: 'iife' }, plugins: [ // 新增的 postcss({ extensions: ['.css'], plugins: [ simplevars(), nested(), cssnext({ warnForDuplicates: false, }), cssnano() ] }), 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: 10002 }), livereload() ] }
現在我們再來執行 npm run build, 後再開啟瀏覽器就可以看到了head裡面新增樣式了,並且已經壓縮的。
注意:在cssnext()中配置了{ warnForDuplicates: false }是因為它和cssnano()都使用了Autoprefixer,會導致一個警告。 我們只需要知道它被執行了兩次(在這個例子中沒什麼壞處)並且取消了警告。
同理我們執行命令 npm run watch 後,修改css,也能實時載入到最新的css了。