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