本文示例如何基于Rollup
和Vue
编写一个HelloWorld的UI库
一、初始化项目
生成package.json
mkdir base-ui
cd base-ui
npm init
安装npm包
npm install --save-dev rollup rollup-plugin-vue vue vue-template-compiler
npm install --save-dev rollup-plugin-babel @babel/core
npm install --save-dev rollup-plugin-node-resolve rollup-plugin-commonjs
npm install --save-dev rollup-plugin-terser rollup-plugin-css-only clean-css
二、配置文件
增加rollup
配置文件 rollup.config.js
,支持umd es iiffe
格式(分别用于node、es6、browser)
import commonjs from 'rollup-plugin-commonjs'
import resolve from 'rollup-plugin-node-resolve'
import babel from 'rollup-plugin-babel'
import vue from 'rollup-plugin-vue'
import { terser } from 'rollup-plugin-terser'
import css from 'rollup-plugin-css-only' // 提取css
import CleanCSS from 'clean-css' // 压缩css
import { writeFileSync } from 'fs' // 写文件
module.exports = {
input: 'src/index.js', // 入口
output: [
{
file: 'dist/base-ui.umd.js', // 打包文件名
name: 'base-ui',
format: 'umd', // 打包模块支持方案,可选 amd, cjs, es, iife, umd
}, {
file: 'dist/base-ui.es.js',
format: 'es'
}, {
name: 'base-ui',
file: 'dist/base-ui.min.js',
format: 'iife'
}],
plugins: [
// css({output: 'dist/base-ui.css'}),
css({ output(style) {
// 压缩 css 写入 dist/base-ui.css
writeFileSync('dist/base-ui.css', new CleanCSS().minify(style).styles)
} }),
vue({
// css: false 将<style>块转换为导入语句,rollup-plugin-css-only可以提取.vue文件中的样式
css: false,
normalizer : '~rollup-plugin-vue/runtime/normalize',
// styleInjector : '~rollup-plugin-vue/runtime/browser',
}),
// terser(),
resolve(),
babel({
exclude: ['node_modules/**']
}),
commonjs()
],
external: [ // 不被打包的库
'vue'
]
}
插件说明
-
rollup-plugin-vue
:负责处理vue
文件,相当于webpack
的vue-loader
。可选参数见这里
5.0以后的rollup-plugin-vue
需要明确指定normalizer : '~rollup-plugin-vue/runtime/normalize',
,否则打包输出文件有__vue_normalize__
相关的引用错误。
2 rollup-plugin-commonjs
该插件负责将Commonjs模块转化成ES6以便rollup打包。很多npm包都是commonjs模块,需要结合此插件一起使用
-
rollup-plugin-node-resolve
rollup只能加载相对路径模块(即通过/
,./
,../
引入的模块),而三方模块(node_modules
里模块)有两种方式打包:-
rollup.config.js
配置为external
资源: 输出bundle中不包含此模块,作为external
外部资源引入,由使用该bundle组件库的客户程序安装
-
// rollup.config.js
export default {
entry: 'src/index.js',
dest: 'bundle.js',
format: 'cjs',
external: [ 'vue' ] // <-- suppresses the warning
};
此时,需要在组件库的package.json
中增加外部依赖
"dependencies": {
"vue": "^2.5.0"
}
客户端程序安装该组件库时会自动安装dependencies
定义的模块
-
rollup-plugin-node-resolve
:该插件可以将三方模块包含在输出bundle中。具体见官网介绍
rollup-plugin-babel
: 在rollup项目中使用babel,详细见这里rollup-plugin-terser
: 压缩输出后jsrollup-plugin-css-only
: 提取css为独立文件clean-css
:压缩css
package.json
最终代码为:
{
"name": "base-ui",
"version": "1.0.0",
"description": "A demo for how to create a UI library with Rollup",
"main": "index.js",
"scripts": {
"build": "rollup -c",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.7.4",
"clean-css": "^4.2.1",
"node-sass": "^4.13.0",
"rollup": "^1.27.8",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-css-only": "^1.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-terser": "^5.1.2",
"rollup-plugin-vue": "^5.1.2",
"vue-template-compiler": "^2.6.10"
}
}
三、开发组件库
3.1 开发组件
src/button/index.vue
编写UI组件
<template>
<h1>Button</h1>
</template>
<script>
export default {
name: 'my-buttom',
created() {
console.log('hello world')
}
}
</script>
3.2 打包全部组件
src/index.js
输出组件。其中install
函数可使组件库当做Vue插件使用,全局注入组件库。请参考VUE插件
import Button from './button/Index.vue'
const components = [Button];
// 全局注入组件
const install = function(Vue) {
if (!Vue || install.installed) return
components.forEach(component => {
Vue.component(component.name, component);
})
}
if (typeof window != 'undefined' && window.Vue) {
install(window.Vue)
}
export {
Button
}
export default {
install
};
npm run build
输出文件dist/base-ui.umd.js
如下
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global['base-ui'] = factory());
}(this, (function () { 'use strict';
var script = {
name: 'my-button',
created() {
console.log('hello world');
}
};
...
var index = {
install
};
export default index;
export { __vue_component__ as Button};
})));
3.3 输出单独组件
输出单独组件以支持按需加载
rollup.component.config.js
增加用于输出组件的配置文件
import commonjs from 'rollup-plugin-commonjs'
import resolve from 'rollup-plugin-node-resolve'
import babel from 'rollup-plugin-babel'
import vue from 'rollup-plugin-vue'
import { terser } from 'rollup-plugin-terser'
import css from 'rollup-plugin-css-only' // 提取css
import CleanCSS from 'clean-css' // 压缩css
import { writeFileSync } from 'fs' // 写文件
module.exports = {
input: 'src/Button/index.js', // 入口
output: {
file: 'dist/button/index.js',
format: 'es'
},
plugins: [
css({ output(style) {
// 压缩 css 写入 dist/base-ui.css
writeFileSync('dist/button/index.css', new CleanCSS().minify(style).styles)
} }),
vue({
// css: false 将<style>块转换为导入语句,rollup-plugin-css-only可以提取.vue文件中的样式
css: false,
normalizer : '~rollup-plugin-vue/runtime/normalize',
// styleInjector : '~rollup-plugin-vue/runtime/browser',
}),
// terser(),
resolve(),
babel({
exclude: ['node_modules/**']
}),
commonjs()
]
}
执行命令rollup -c rollup.component.config.js
输出组件
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global['base-ui'] = factory());
}(this, (function () { 'use strict';
var script = {
name: 'my-button',
created() {
console.log('hello world');
}
};
...
export { __vue_component__ as Button};
})));
四、测试组件库
4.1 创建测试项目
vue create examples
创建项目,用于模拟实际项目引入组件库
全局引入
examples/src/main.js
中引入组件,全局注入组件
import MyComponent from '../../dist/base-ui.es'
import MyComponent from '../../dist/base-ui.css'
Vue.use(MyComponent)
examples/src/components/HelloWorld.vue
中使用组件
<template>
<div id="app">
<my-index></my-index>
</div>
</template>
按需引入
src/components/HelloWorld.vue
中引入Button
...
import { Button } from '../../../dist/button/index.es'
export default {
components: {
[Button.name]: Button
},
}
...
bable-plugin-import
bable-plugin-import
可以帮助用户方便地实现按需加载
bable.config.js
配置文件中增加配置(如下为mand-mobile配置):
{
"plugins": [
["import", {
"libraryName": "mand-mobile", // 组件库名称
"libraryDirectory": "lib" // 组件所在目录
}]
]
}
import { Button } from 'mand-mobile'
babel-plugin-import
会将以上引入语句转换为下面写法
import Button from 'mand-mobile/lib/button'
4.2 测试
组件项目package,json
下增加执行命令, 启动组件库和示例项目的开发模式
"scripts": {
"dev": "rollup -c --watch",
"example": "cd examples && npm run serve",
...
}
组件项目 package.json
里增加入口文件
...
"main": "dist/base-ui.umd.js",
"module": "dist/base-ui.es.js",
"unpkg": "dist/base-ui.min.js",
...
Issues
examples项目里从组件输出目录(/dist)引入组件时默认会启动eslint,编译会报语法错误。暂时取消lint
源码:https://github.com/guolixincl/examples/tree/master/rollup/base-ui
参考文章