轉發:基於rollup實現按需加載的前端組件庫


rollup 是一個 JavaScript 模塊打包器,在功能上要完成的事和webpack性質一樣,就是將小塊代碼編譯成大塊復雜的代碼,例如 library 或應用程序。在平時開發應用程序時,我們基本上選擇用webpack,相比之下,rollup.js更多是用於library打包,我們熟悉的vue、react、vuex、vue-router等都是用rollup進行打包的。

rollup安裝與使用

首先是安裝:

npm i rollup -g        # 全局安裝
npm i rollup -D        # 項目本地安裝
復制代碼

打包一個js文件

如下新建一個項目,並安裝rollup,創建兩個文件:hello.js和index.js

如果是全局安裝,直接在項目根目錄下執行:

rollup -i src/index.js -o dist/bundle.js -f es**

如果是項目本地安裝,在package.json的script字段中添加:

"dev": "rollup -i src/index.js -o dist/bundle.js -f es",然后執行npm run dev

在這里,我們以本地安裝為例。如下,rollup在命令行輸出了打包結果。

在這段指令中:

  • -i指定要打包的文件,-i--input的縮寫。
  • src/index.js-i的參數,即打包入口文件。
  • -o指定輸出的文件,是--output.file--file的縮寫。(如果沒有這個參數,則直接輸出到控制台)
  • dist/bundle.js-o的參數,即輸出文件。
  • -f指定打包文件的格式,-f--format的縮寫。
  • es-f的參數,表示打包文件使用ES6模塊規范。

rollup支持的打包文件的格式有amd, cjs, es\esm, iife, umd。其中,amd為AMD標准,cjs為CommonJS標准,esm\es為ES模塊標准,iife為立即調用函數, umd同時支持amd、cjs和iife。

rollup配置文件

在項目開發中,我們通常會使用配置文件,這不僅可以簡化命令行操作,同時還能啟用rollup的高級特性。

在項目根目錄下創建rollup.config.js

export default {
  input: "./src/index.js",
  output: [
    {
      file: './dist/my-lib-umd.js',
      format: 'umd',
      name: 'myLib'   
      //當入口文件有export時,'umd'格式必須指定name
      //這樣,在通過<script>標簽引入時,才能通過name訪問到export的內容。
    },
    {
      file: './dist/my-lib-es.js',
      format: 'es'
    },
    {
      file: './dist/my-lib-cjs.js',
      format: 'cjs'
    }
  ]
}
復制代碼

使用Rollup的配置文件,可以使用rollup --config或者rollup -c指令。

//修改package.json的script字段

"dev": "rollup -c"                 // 默認使用rollup.config.js
"dev": "rollup -c my.config.js"    //使用自定義的配置文件,my.config.js
復制代碼

src/index.js內容:

import { hello } from './hello'
hello()
export const world = 'world'
復制代碼

打包后的文件: 可以看出,同樣的入口文件,es格式的文件體積最小。

rollup插件

上面我們知道了rollup的基礎用法,在實際應用中,會有很多更復雜的需求,比如,怎樣支持es6語法,怎樣打包.vue文件,怎樣壓縮我們js的代碼等等。在rollup中,我們借助插件來完成。

在webpack中,使用loader對源文件進行預處理,plugin完成構建打包的特定功能需求。rollup的plugin兼具webpack中loader和plugin的功能。

一些常用的插件。

rollup-plugin-babel

rollup-plugin-babel用於轉換es6語法。

src/hello.js中的內容改寫成:

export const hello = () => {
  console.log('hello world')
}
復制代碼

在未使用babel插件的情況下,打包結果:

使用babel插件:

npm i rollup-plugin-babel @babel/core @babel/preset-env --D

//rollup.dev.js
import babel from 'rollup-plugin-babel'
export default {
  input: ...,
  output: ...,
  plugins:[
    babel({
        exclude: 'node_modules/**'
    })
  ]
}
復制代碼

在項目根目錄創建.babelrc文件。

{
  "presets": [
      [
        "@babel/preset-env"
      ]
    ]
}
復制代碼

再次打包:

rollup-plugin-commonjs

rollup默認是不支持CommonJS模塊的,自己寫的時候可以盡量避免使用CommonJS模塊的語法,但有些外部庫的是cjs或者umd(由webpack打包的),所以使用這些外部庫就需要支持CommonJS模塊。

新建一個src/util.js文件,內容如下:

module.exports = {
  a: 1
}
復制代碼

src/index.js中引入util.js

import util from './util'
console.log(util.a)
復制代碼

npm run dev打包會報錯:

這就需要使用rollup-plugin-commonjs,首先,npm i rollup-plugin-commonjs --D.

rollup.config,js中加入:

import commonjs from 'rollup-plugin-commonjs'
export default {
  input: ...,
  output: ...,
  plugins:[
    commonjs()
  ]
}
復制代碼

npm run dev打包,沒有報錯。

我們還可以在代碼使用require引入模塊:

// src/index.js
const util = require('./util')
console.log(util.a)
復制代碼

rollup-plugin-commonjs可以識別require語法,並打包成es模塊語法,打包的出的my-lib-es.js的內容如下:

var util = {
  a: 1
};

console.log(util.a);

var src = {

};

export default src;
復制代碼

rollup-plugin-postcss

處理css需要用到的插件是rollup-plugin-postcss。它支持css文件的加載、css加前綴、css壓縮、對scss/less的支持等等。

首先,安裝,npm i rollup-plugin-postcss postcss --D,然后在rollup.config.js中配置:

import postcss from 'rollup-plugin-postcss'
export default {
  input: ...,
  output: ...,
  plugins:[
    postcss()
  ]
}
復制代碼

然后,新建一個test.css,在index.js中引入。 打包后得到的umd文件:

(function (factory) {
  typeof define === 'function' && define.amd ? define(factory) :
  factory();
}((function () { 'use strict';

  function styleInject(css, ref) {
    if ( ref === void 0 ) ref = {};
    var insertAt = ref.insertAt;

    if (!css || typeof document === 'undefined') { return; }

    var head = document.head || document.getElementsByTagName('head')[0];
    var style = document.createElement('style');
    style.type = 'text/css';

    if (insertAt === 'top') {
      if (head.firstChild) {
        head.insertBefore(style, head.firstChild);
      } else {
        head.appendChild(style);
      }
    } else {
      head.appendChild(style);
    }

    if (style.styleSheet) {
      style.styleSheet.cssText = css;
    } else {
      style.appendChild(document.createTextNode(css));
    }
  }

  var css_248z = "body{\r\n  color: green;\r\n}";
  styleInject(css_248z);

})));
復制代碼

導入的css文件將用於生成style標簽,插入到head中。

我們新建一個測試文件,引入該umd文件。可以看到head中有我們在test.css寫入的內容。

<body>
  test css
</body>
<script src="../dist/my-lib-umd.js"></script>
復制代碼

css加前綴

借助autoprefixer插件來給css3的一些屬性加前綴。安裝npm i autoprefixer@8.0.0 --D,配置:

import postcss from 'rollup-plugin-postcss'
import autoprefixer from 'autoprefixer'
export default {
  input: ...,
  output: ...,
  plugins:[
    postcss({
      plugins: [  
        autoprefixer()  
      ]
    })
  ]
}
復制代碼

使用autoprefixer除了以上配置,還需要配置browserslist,有2種方式,一種是建立.browserslistrc文件,另一種是直接在package.json里面配置,我們在package.json中,添加"browserslist"字段。

"browserslist": [
  "defaults",
  "not ie < 8",
  "last 2 versions",
  "> 1%",
  "iOS 7",
  "last 3 iOS versions"
]
復制代碼

修改test.css的內容:

body{
  color: green;
  display: flex;
}
復制代碼

打包,刷新剛才的測試頁面。

css壓縮

cssnano對打包后的css進行壓縮。使用方式也很簡單,和autoprefixer一樣,安裝cssnano,然后配置。

plugins:[
  postcss({
    plugins: [
      autoprefixer(),
      cssnano()
    ]
  })
]
復制代碼

抽離單獨的css文件

rollup-plugin-postcss可配置是否將css單獨分離,默認沒有extract,css樣式生成style標簽內聯到head中,配置了extract,就會將css抽離成單獨的文件。

postcss({
  plugins: [
    autoprefixer(),
    cssnano()
  ],
  extract: 'css/index.css'  
})
復制代碼

當然,在頁面也需要單獨引入打包好的css文件。

支持scss/less

實際項目中我們不太可能直接寫css,而是用scss或less等預編譯器。rollup-plugin-postcss默認集成了對scss、less、stylus的支持,在我們項目中,只要配置了rollup-plugin-postcss,就可以直接使用這些css預編譯器,很方便的。

rollup-plugin-vue

rollup-plugin-vue用於處理.vue文件。vue2和vue3項目所用的rollup-plugin-vue版本不一樣,vue的編譯器也不一樣

  • vue2:rollup-plugin-vue^5.1.9 + vue-template-compiler
  • vue3:rollup-plugin-vue^6.0.0 + @vue/compiler-sfc

以vue2為例:

npm i rollup-plugin-vue@5.1.9 vue-template-compiler --D

rollup.dev.js中加入rollup-plugin-vue

import vue from 'rollup-plugin-vue'
export default {
  ...
  plugins:[
    vue()
  ]
}
復制代碼

新建一個vue文件,並修改src/index.js

npm run dev打包,我們來看看生成的umd文件。

測試umd文件:

<body>
  <div id="app">
    <hello></hello>
  </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="../dist/my-lib-umd.js"></script>
<script>
  Vue.use(myLib)
  new Vue({
    el: '#app'
  })
</script>
復制代碼

組件使用成功,說明我們的配置可以編譯、打包.vue文件了。

rollup-plugin-vue也是默認支持scss、less、stylus,可以在項目中直接使用。給.vue文件中的css自動加前綴,需要在rollup-plugin-vue中配置。更多配置參考rollup-plugin-vue

import vue from 'rollup-plugin-vue'
import autoprefixer from 'autoprefixer'  //同樣要配置browserslist
import cssnano from 'cssnano'
export default {
  ...
  plugins:[
    vue({
      style: {
        postcssPlugins: [
          autoprefixer(),
          cssnano()
        ]
      }
    })
  ]
}
復制代碼

rollup-plugin-terser

在生產環境中,代碼壓縮是必不可少的。我們使用rollup-plugin-terser進行代碼壓縮。

import { terser } from 'rollup-plugin-terser'
export default {
  ...
  plugins:[
    terser()
  ]
}
復制代碼

在上面的過程中,我們都是打包好文件,然后通過script引入,或npm link然后在別的項目中調試,這更像是組件庫的調試方法。如果我們用rollup打包一個應用,它能否像webpack那樣熱更新呢?答案是可以的。我們需要借助rollup-plugin-serverollup-plugin-livereload

rollup-plugin-serve、rollup-plugin-livereload

這兩個插件常常一起使用,rollup-plugin-serve用於啟動一個服務器,rollup-plugin-livereload用於文件變化時,實時刷新頁面。

import serve from 'rollup-plugin-serve'
import livereload from 'rollup-plugin-livereload'
export default {
  ...
  plugins:[
    serve({
      contentBase: '',  //服務器啟動的文件夾,默認是項目根目錄,需要在該文件下創建index.html
      port: 8020   //端口號,默認10001
    }),    
    livereload('dist')   //watch dist目錄,當目錄中的文件發生變化時,刷新頁面
  ]
}
復制代碼

我們需要在index.html手動加入打包后的文件,js或者css,因為此時並沒有自動注入。然后訪問http://localhost:8020就可以看到index.html中的內容。

然而,此時修改src中的文件,頁面並不會實時刷新,因為dist目錄下的文件並沒有更新。 rollup監聽源文件的改動很簡單,就是在執行打包命令時,添加 -w 或者 --watch

//package.json
"scripts": {
   "dev": "rollup -wc"
},
復制代碼

大功告成,再修改源文件的代碼,你就會發現瀏覽器實時更新了。

打包按需加載的組件庫

都到這里了,打包按需加載組件就太簡單了。

對於組件庫項目,支持按需加載需要滿足:組件庫以ES模塊化方式導出。 而rollup本來就支持ES模塊的導出。

新建兩個vue組件,hello和test:

修改src/index.js:

import Hello from "./components/Hello"
import Test from "./components/Test"
function install(Vue){
  Vue.use(Hello)
  Vue.use(Test)
}

/***
在es模塊中, 能被按需引入的變量需要用這些方式導出:
export const a = 1
export function a(){}
export { a, b }
而不能使用export default
***/

export {    
  Hello,
  Test
}

export default install  //umd
復制代碼

修改rollup.config.js如下:

import babel from 'rollup-plugin-babel'
import commonjs from 'rollup-plugin-commonjs'
import vue from 'rollup-plugin-vue'
import autoprefixer from 'autoprefixer'
export default {
  input: "./src/index.js",
  output: [
    {
      file: './dist/my-lib-umd.js',
      format: 'umd',
      name: 'myLib'
    },
    {
      file: './dist/my-lib-es.js',
      format: 'es'
    },
    {
      file: './dist/my-lib-cjs.js',
      format: 'cjs'
    }
  ],
  plugins:[
    babel({
        exclude: 'node_modules/**'
    }),
    vue({
      style: {
        postcssPlugins: [
          autoprefixer()
        ]
      }
    }),
    commonjs()
  ],
  external:[  //外部庫, 使用'umd'文件時需要先引入這個外部庫
    'vue'
  ]
}
復制代碼

打包后,修改package.json:

"main": "dist/my-lib-cjs.js",
"module": "dist/my-lib-es.js",
復制代碼

然后就可以在測試項目中進行測試了。具體可以參考怎樣在本地調試組件庫

import { Hello } from "my-lib-new"
Vue.use(Hello)
復制代碼

至此,我們用rollup打包按需加載的組件庫就完成了,整體感覺,要比webpack方便很多,按需加載組件的時候也不需要借助插件,在類庫打包方面是挺優秀的了。


作者:Alaso
鏈接:https://juejin.cn/post/6934698510436859912
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM