在上一篇文章中,咱们学习了用webpack打包一个组件库。这次咱们来学习怎么用rollup打包一个组件库。

用webpack打包一个按需加载的vue组件库

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.jsimport 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.jsconst 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'  //同样要配置browserslistimport 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 = 1export 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不便很多,按需加载组件的时候也不须要借助插件,在类库打包方面是挺优良的了。