10分鐘快速精通rollup.js——前置學習之rollup.js插件篇

前言

本文是《10分鐘快速精通rollup.js——Vue.js源碼打包過程深度分析》的前置學習教程,講解的知識點以理解Vue.js打包源碼爲目標,不會作過多地展開。教程將保持rollup.js系列教程的一向風格,大部分知識點都將提供可運行的代碼案例和實際運行的結果,讓你們經過教程就能夠看到實現效果,省去親自上機測試的時間。vue

學習本教程須要理解buble、flow和terser模塊的用途,還不瞭解的小夥伴能夠查看這篇教程:《10分鐘快速精通rollup.js——前置學習之基礎知識篇》node

1. rollup-plugin-buble插件

Convert ES2015 with buble.webpack

buble插件的用途是在rollup.js打包的過程當中進行代碼編譯,將ES6+代碼編譯成ES2015標準,首先在項目中引入buble插件:web

npm i -D rollup-plugin-buble
複製代碼

修改./src/vue/buble/index.js的源碼,寫入以下內容:npm

const a = 1 // ES6新特性:const
let b = 2 // ES6新特性:let
const c = () => a + b // ES6新特性:箭頭函數
console.log(a, b, c())
複製代碼

修改rollup.plugin.config.js配置文件:bash

import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import buble from 'rollup-plugin-buble'

export default {
  input: './src/vue/buble/index.js',
  output: [{
    file: './dist/index-plugin-cjs.js',
    format: 'cjs'
  }],
  plugins: [
    resolve(),
    commonjs(),
    buble()
  ]
}
複製代碼

應用rollup.js進行編譯:babel

$ rollup -c rollup.plugin.config.js 
./src/vue/buble/index.js  ./dist/index-plugin-cjs.js...
created ./dist/index-plugin-cjs.js in 35ms
複製代碼

查看生成文件的內容:markdown

$ cat dist/index-plugin-cjs.js 
'use strict';

var a = 1;
var b = 2;
var c = function () { return a + b; };
console.log(a, b, c());
複製代碼

經過node執行打包後的代碼:app

$ node dist/index-plugin-cjs.js 
1 2 3
複製代碼

2. rollup-plugin-alias插件

Provide an alias for modules in Rollupdom

alias插件提供了爲模塊起別名的功能,用過webpack的小夥伴應該對這個功能很是熟悉,首先在項目中引入alias插件:

npm i -D rollup-plugin-alias
複製代碼

建立src/vue/alias目錄,並建立一個本地測試庫lib.js和測試代碼index.js:

mkdir -p src/vue/alias
touch src/vue/alias/index.js
touch src/vue/alias/lib.js
複製代碼

在lib.js中寫入以下內容:

export function square(n) {
  return n * n
}
複製代碼

在index.js中寫入以下內容:

import { square } from '@/vue/alias/lib' // 使用別名

console.log(square(2))
複製代碼

修改rollup.plugin.config.js的配置文件:

import alias from 'rollup-plugin-alias'
import path from 'path'

const pathResolve = p => path.resolve(__dirname, p)

export default {
  input: './src/vue/alias/index.js',
  output: [{
    file: './dist/index-plugin-es.js',
    format: 'es'
  }],
  plugins: [
    alias({
      '@': pathResolve('src')
    })
  ]
}
複製代碼

這裏咱們提供了一個pathResolve方法,用於生成絕對路徑,引入alias插件中咱們傳入一個對象做爲參數,對象的key是模塊中使用的別名,對象的value是別名對應的真實路徑。使用rollup.js進行打包:

$ rollup -c rollup.plugin.config.js 

./src/vue/alias/index.js  ./dist/index-plugin-es.js...
created ./dist/index-plugin-es.js in 23ms
複製代碼

查看打包後的代碼,能夠看到正確識別出別名對應的路徑:

$ cat dist/index-plugin-es.js 
function square(n) {
  return n * n
}

console.log(square(2));
複製代碼

3. rollup-plugin-flow-no-whitespace插件

flow插件用於在rollup.js打包過程當中清除flow類型檢查部分的代碼,咱們修改rollup.plugin.config.js的input屬性:

input: './src/vue/flow/index.js',
複製代碼

嘗試直接打包flow的代碼:

$ rollup -c rollup.plugin.config.js 

./src/vue/flow/index.js  ./dist/index-plugin-cjs.js...
[!] Error: Unexpected token
src/vue/flow/index.js (2:17)
1: /* @flow */
2: function square(n: number): number {
                    ^
3:   return n * n
4: }
Error: Unexpected token
複製代碼

能夠看到rollup.js會拋出異常,爲了解決這個問題咱們引入flow插件:

npm i -D rollup-plugin-flow-no-whitespace
複製代碼

修改配置文件:

import flow from 'rollup-plugin-flow-no-whitespace'

export default {
  input: './src/vue/flow/index.js',
  output: [{
    file: './dist/index-plugin-cjs.js',
    format: 'cjs'
  }],
  plugins: [
    flow()
  ]
}
複製代碼

從新運行打包:

$ rollup -c rollup.plugin.config.js 
./src/vue/flow/index.js  ./dist/index-plugin-cjs.js...
created ./dist/index-plugin-cjs.js in 40ms
複製代碼

查看打包後的源碼:

$ cat ./dist/index-plugin-cjs.js 
'use strict';

/*  */
function square(n) {
  return n * n
}

console.log(square(2));
複製代碼

能夠看到flow的代碼被成功清除,可是/* @flow */被修改成了/* */,這個問題咱們可使用terser插件後進行修復,去除註釋。

4. rollup-plugin-replace插件

Replace content while bundling

replace插件的用途是在打包時動態替換代碼中的內容,首先引入replace插件:

npm i -D rollup-plugin-replace
複製代碼

建立src/vue/replace文件夾和index.js測試文件:

mkdir -p src/vue/replace
touch src/vue/replace/index.js
複製代碼

在index.js文件中寫入以下內容:

const a = 1
let b = 2
if (__SAM__) { // 使用replace值__SAM__,注意這個值沒有定義,若是直接運行會報錯
  console.log(`__SAM__,${a},${b},${c}`) // 使用__SAM__,打包時會被替換
}
複製代碼

修改rollup.plugin.config.js配置文件:

import buble from 'rollup-plugin-buble'
import replace from 'rollup-plugin-replace'

export default {
  input: './src/vue/replace/index.js',
  output: [{
    file: './dist/index-plugin-cjs.js',
    format: 'cjs'
  }],
  plugins: [
    replace({
      __SAM__: true
    }),
    buble()
  ]
}
複製代碼

咱們向replace插件傳入一個對象,key是__SAM__,value是true。因此rollups.js打包時就會將__SAM__替換爲true。值得注意的是代碼使用了ES6了特性,因此須要引入buble插件進行編譯,咱們執行打包指令:

$ rollup -c rollup.plugin.config.js 
./src/vue/replace/index.js  ./dist/index-plugin-cjs.js...
created ./dist/index-plugin-cjs.js in 28ms
複製代碼

查看打包結果:

$ cat dist/index-plugin-cjs.js 
'use strict';

var a = 1;
var b = 2;
{
  console.log(("true," + a + "," + b + "," + c));
}
複製代碼

能夠看到__SAM__被正確替換爲了true。若是你們使用的是WebStorm編輯器,使用flow語法會出現警告,這時咱們須要打開設置,進入Languages & Frameworks > Javascript,將Javascript language version改成Flow。

WebStorm flow配置
除此以外,使用__SAM__也會引起警告。
類型錯誤
解決這個問題的辦法是打開flow/test.js,添加__SAM__的自定義變量(declare var),這樣警告就會消除:

declare type Test = {
  a?: number; // a的類型爲number,能夠爲空
  b?: string; // b的類型爲string,能夠爲空
  c: (key: string) => boolean; // c的類型爲function,只能包含一個參數,類型爲string,返回值爲boolean,注意c不能爲空
}

declare var __SAM__: boolean; // 添加自定義變量
複製代碼

5. rollup-plugin-terser插件

Rollup plugin to minify generated es bundle

terser插件幫助咱們在rollup.js打包過程當中實現代碼壓縮,首先引入terser插件:

npm i -D rollup-plugin-terser
複製代碼

修改src/vue/replace/index.js的源碼,這裏咱們作一輪綜合測試,將咱們以前學習的插件所有應用進來:

/* @flow */
import { square } from '@/vue/alias/lib' // 經過別名導入本地模塊
import { random } from 'sam-test-data' // 導入es模塊
import { a as cjsA } from 'sam-test-data-cjs' // 導入commonjs模塊

const a: number = 1 // 經過flow進行類型檢查
let b: number = 2 // 使用ES6新特性:let
const c: string = '' // 加入非ascii字符
if (__SAM__) { // 使用replace字符串
  console.log(`__SAM__,${a},${b},${c}`) // 使用ES6新特性``模板字符串
}
export default {
  a, b, c, d: __SAM__, square, random, cjsA
} // 導出ES模塊
複製代碼

咱們但願經過上述代碼驗證如下功能:

  • replace插件:代碼中的__SAM__被正確替換;
  • flow插件:正確去掉flow的類型檢查代碼;
  • buble插件:將ES6+代碼編譯爲ES2015;
  • alias插件:將模塊中'@'別名替換爲'src'目錄;
  • commonjs插件:支持CommonJS模塊;
  • resovle插件:合併外部模塊代碼;
  • terser插件:代碼最小化打包。

修改rollup.plugin.config.js配置文件:

import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import buble from 'rollup-plugin-buble'
import replace from 'rollup-plugin-replace'
import flow from 'rollup-plugin-flow-no-whitespace'
import { terser } from 'rollup-plugin-terser'
import alias from 'rollup-plugin-alias'
import path from 'path'

const pathResolve = p => path.resolve(__dirname, p)

export default {
  input: './src/vue/replace/index.js',
  output: [{
    file: './dist/index-plugin-es.js',
    format: 'es'
  }],
  plugins: [
    replace({
      __SAM__: true
    }),
    flow(),
    buble(),
    alias({
      '@': pathResolve('src')
    }),
    commonjs(),
    resolve(),
    terser({
      output: {
        ascii_only: true // 僅輸出ascii字符
      },
      compress: {
        pure_funcs: ['console.log'] // 去掉console.log函數
      }
    }),
  ]
}
複製代碼

terser插件的配置方法與API模式基本一致,打包代碼:

$ rollup -c rollup.plugin.config.js 
./src/vue/replace/index.js  ./dist/index-plugin-es.js...
created ./dist/index-plugin-es.js in 308ms
複製代碼

查看打包後的代碼文件:

$ cat dist/index-plugin-es.js 
function square(a){return a*a}function random(a){return a&&a%1==0?Math.floor(Math.random()*a):0}var a$1=Math.floor(10*Math.random()),b$1=Math.floor(100*Math.random());function random$1(a){return a&&a%1==0?Math.floor(Math.random()*a):0}var _samTestDataCjs_0_0_1_samTestDataCjs={a:a$1,b:b$1,random:random$1},_samTestDataCjs_0_0_1_samTestDataCjs_1=_samTestDataCjs_0_0_1_samTestDataCjs.a,a$2=1,b$2=2,c="\ud83d\ude00",index={a:a$2,b:b$2,c:c,d:!0,square:square,random:random,cjsA:_samTestDataCjs_0_0_1_samTestDataCjs_1};export default index;
複製代碼

能夠看到各項特性所有生效,嘗試經過babel-node運行代碼:

$ babel-node 
> require('./dist/index-plugin-es')
{ default:
   { a: 1,
     b: 2,
     c: '',
     d: true,
     square: [Function: square],
     random: [Function: random],
     cjsA: 4 } }
複製代碼

代碼成功運行,說明打包過程成功。

6. intro和outro配置

intro和outro屬性與咱們以前講解的banner和footer屬性相似,都是用來爲代碼添加註釋。那麼這四個屬性之間有什麼區別呢?首先了解一下rollup.js官網對這四個屬性的解釋:

  • intro:在打包好的文件的塊的內部(wrapper內部)的最頂部插入一段內容
  • outro:在打包好的文件的塊的內部(wrapper內部)的最底部插入一段內容
  • banner:在打包好的文件的塊的外部(wrapper外部)的最頂部插入一段內容
  • footer:在打包好的文件的塊的外部(wrapper外部)的最底部插入一段內容

簡單地說就是intro和outro添加的註釋在代碼塊的內部,banner和footer在外部,下面舉例說明,修改src/plugin/main.js代碼:

const a = 1
console.log(a)
export default a
複製代碼

修改rollup.config.js的配置:

export default {
  input: './src/plugin/main.js',
  output: [{
    file: './dist/index-cjs.js',
    format: 'cjs',
    banner: '// this is banner',
    footer: '// this is footer',
    intro: '// this is a intro comment',
    outro: '// this is a outro comment',
  }]
}
複製代碼

打包代碼:

$ rollup -c

./src/plugin/main.js  ./dist/index-cjs.js...
created ./dist/index-cjs.js in 11ms
複製代碼

輸出結果:

$ cat dist/index-cjs.js 
// this is banner
'use strict';

// this is a intro comment

const a = 1;
console.log(a);

module.exports = a;

// this is a outro comment
// this is footer
複製代碼

能夠看到banner和footer的註釋在最外層,而intro和outro的註釋在內層,intro的註釋在'use strict'下方,因此若是要給代碼最外層包裹一些元素,如module.exports或export default之類的,須要使用intro和outro,在Vue.js源碼打包過程當中就使用了intro和outro爲代碼添加模塊化特性。咱們還能夠將intro和outro配置寫入plugins的方法來實現這個功能:

export default {
  input: './src/plugin/main.js',
  output: [{
    file: './dist/index-cjs.js',
    format: 'cjs',
    banner: '// this is banner',
    footer: '// this is footer'
  }],
  plugins: [
    {
      intro: '// this is a intro comment',
      outro: '// this is a outro comment'
    }
  ]
}
複製代碼

該配置文件生成的效果與以前徹底一致。

總結

本教程主要爲你們講解了如下知識點:

  • rollup-plugin-buble插件:編譯ES6+語法爲ES2015,無需配置,比babel更輕量;
  • rollup-plugin-alias插件:替換模塊路徑中的別名;
  • rollup-plugin-flow-no-whitespace插件:去除flow靜態類型檢查代碼;
  • rollup-plugin-replace插件:替換代碼中的變量爲指定值;
  • rollup-plugin-terser插件:代碼壓縮,取代uglify,支持ES模塊。
  • intro和outro配置:在代碼塊內添加代碼註釋。
相關文章
相關標籤/搜索