乐趣区

关于javascript:rollup从入门到打包一个按需加载的组件库

在上一篇文章中,咱们学习了用 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.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 不便很多,按需加载组件的时候也不须要借助插件,在类库打包方面是挺优良的了。

退出移动版