进阶

组件库按需引入

在目前,所有的组件会被打包进一个文件,组件库是一骨碌加载完所有组件,同时也会打包和加载多余的代码。对于小项目这样没有问题,但是当组件库越来越庞大、丰富,特别是像我们带业务逻辑的非js库,代码量会更大,如果不管不顾的一通加载完所有资源,后期肯定会带来业务方面的体验问题。

所以首要的问题是实现源代码的按需引入,而按需引入的前提是实现源码包按独立组件分割和的拆分打包。

代码分拆

单个组件独立构建打包的思路就是给打包工具提供多个独立的入口,根据入口收集其所依赖的资源。一个组件入口产出一个文件

webpack

使用 webpack 配置多入口的方式来按模块拆分打包,每一个模块作为一个入口,与此同时产出对应的文件。

webpack 的配置比较简单,不展开.

实际构建 library 使用 webpack 有不小的缺点, 应为 webpack 产出后的文件中带有一层包裹代码,这种情况下在碎片化的组件库中反而会使打包体积变大,无法起到‘瘦身’的效果。如下的 webpack 包裹代码:

/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {'use strict';/* unused harmony export square *//* harmony export (immutable) */ __webpack_exports__['a'] = cube;function square(x) {return x * x;}function cube(x) {return x * x * x;}
});

哪些额外的代码看着有点不那么清爽.

rollup

使用 rollup来打包 library,rollup相较于 webpack 在打包体积上会跟小,更加适合 .

rollup 的特点:

  • Tree Shaking: 自动移除未使用的代码, 输出更小的文件
  • Scope Hoisting: 所有模块构建在一个函数内, 执行效率更高
  • Config 文件支持通过 ESM 模块格式书写
  • 可以一次输出多种格式:
    • 模块规范: IIFE, AMD, CJS, UMD, ESM
    • Development 与 production 版本: .js, .min.js

是驴是马拉出来溜溜~~

全局安装 rollup
npm install --global rollup
// or
cnpm install --global rollup

rollup 的迭代比较快,这里稍微留意一下 rollup 的版本,部分插件可能不兼容

添加rollup.config.js

在项目根目录下创建 rollup.config.js 文件:

// rollup.config.js
export default {input: 'packages/index.js',output: {file: 'lib/app.all.js',format: 'cjs'}
};
  • input:构建入口
  • format:编译打包格式
  • file:编译后输出目录

就这么简单,执行以下命令开始将装个 packages 构建构建为一个单文件

rollup -c rollup.config.js
添加 rollup 多文件构建

Rollup 配置文件是一个标准 ES6 模块,默认到处一个对象,也可以到处一个对象用来构建多个模块

// rollup.config.js
export default [{input: 'packages/a.js',output: {file: 'lib/app.a.js',format: 'cjs'}
},{input: 'packages/b.js',output: {file: 'lib/app.b.js',format: 'cjs'}
}];

packages 目录为组件库源码,相关模块不固定,不适宜写死。对于这个问题通过扫描目录获取所有模块,修改 rollup.config.js :

// rollup.config.js
const fs = require('fs-extra');
const path = require('path');const packages = {};
const dir = path.join(__dirname, '../packages');
const files = fs.readdirSync(dir);
files.forEach(file => {const absolutePath = path.join(dir, file);if (isDir(absolutePath)) {packages[file] =`packages/${file}/index.js`;}
});function createRollupConfig (file, name) {const config = {input: file,output: {file: `lib/index.js` : `lib/${name}/index.js`,format: 'es',name: name,sourcemap: true}}return config
}const buildPackages = []
for (let name in packages) {const file = packages[name]buildPackages.push(createRollupConfig(file, name))
}export default buildPackages;

这里打包文件的格式我们使用 eses是指ES6.这个时候开始构建会报错,因为rollup还不能识别组件库中的 vue 样板代码、语法,同时我们的组件库并不是纯粹的js library, 也需要处理业务组件内引用的样式和图片、字体等。

仅仅是使用 rollup 还不能实现我们的目的,需要借助一系列 rollup 插件来完成

处理vue

.vue文件的编译需要使用rollup-plugin-vue2插件:

npm rollup-plugin-vue2 --save-dev
处理样式

样式处理可以使用 rollup-plugin-css-only插件。由于不喜欢笨拙的css,习惯了scss语法,就直接使用 scss,但其配置就相对要复杂一点。

scss样式处理可以使用rollup-plugin-scss插件,为了灵活的处理样式我使用Postcss

图片处理

html中引入的图片在组件库部署后就无法正常访问了,这里使用 rollup-plugin-url

插件将内嵌的图片编译为 base64 再直接放入 js 文件中。

对于组件库中有较多大尺寸的图片建议直接将图片放入图片服务器,然后通过url 引入,避免打包文件过大的问题.

加入 rollup 插件后的配置:

// rollup.config.js
const fs = require('fs-extra');
const path = require('path');import vue from 'rollup-plugin-vue2'
import postcss from 'rollup-plugin-postcss'
import postcssScss from 'postcss-scss'
import autoprefixer from 'autoprefixer'
import base64 from 'postcss-base64'
import url from 'rollup-plugin-url'import progress from 'rollup-plugin-progress'
import filesize from 'rollup-plugin-filesize';function isDir(dir) {return fs.lstatSync(dir).isDirectory();
}const packages = {};
const dir = path.join(__dirname, '../packages');
const files = fs.readdirSync(dir);
files.forEach(file => {const absolutePath = path.join(dir, file);if (isDir(absolutePath)) {packages[file] =`packages/${file}/index.js`;}
});function createRollupConfig (file, name) {const config = {input: file,output: {file: `lib/${name}/index.js`,format: 'es',name: name,sourcemap: true},plugins: [vue(),postcss({extract: true,parser: postcssScss,plugins: [base64({extensions: ['.png', '.jpeg'],root: './packages/',}),autoprefixer({ add: true }),]}),url({limit: 10 * 1024,//include: ['.svg']}),progress(),filesize()]}return config
}const buildPackages = []
for (let name in packages) {const file = packages[name]buildPackages.push(createRollupConfig(file, name))
}export default buildPackages;

到此可以运行 rollup -c rollup.config.js 打包,实现源代码按依赖关系和目录进行分拆打包:

lib├─message│      index.js|      index.css|      index.js.map├─pay│      index.js|      index.css|      index.js.map├─share│      index.js|      index.css|      index.js.map

打包后的 packages/pay/index.js > lib/pay/index.js :

// lib/pay/index.js
var logo = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTk2QkI4RkE3NjE2MTFFNUE4NEU4RkIxNjQ5MTYyRDgiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTk2QkI4Rjk3NjE2MTFFNUE4NEU4RkIxNjQ5MTYyRDgiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NjU2QTEyNzk3NjkyMTFFMzkxODk4RDkwQkY4Q0U0NzYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NjU2QTEyN0E3NjkyMTFFMzkxODk4RDkwQkY4Q0U0NzYiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5WHowqAAAXNElEQVR42uxda4xd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";var message = {
render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"message"},[_c('el-row',{staticClass:"message-test"},[_c('el-col',{staticClass:"message-row",attrs:{"span":12}},[_c('p',{staticClass:"text"},[_vm._v("message "+_vm._s(_vm.message)+" -- "+_vm._s(_vm.count))])]),_vm._v(" "),_c('el-col',{attrs:{"span":6}},[_c('p',[_vm._v("\n        css backgroud image base64\n      ")]),_vm._v(" "),_c('div',{staticClass:"tops"}),_vm._v(" "),_c('hr'),_vm._v(" "),_c('p',[_vm._v("\n        html img 内嵌 image base64\n      ")]),_vm._v(" "),_c('img',{staticStyle:{"width":"100px"},attrs:{"src":_vm.imgUrl}})])],1)],1)},
staticRenderFns: [],name: 'x-message',props: {message: String,},data: function () {return {count: '2233hahaha',imgUrl: logo}},created: function () {console.log('logo:', this.imgUrl);}
};message.install = function (Vue) {Vue.component(message.name, message);
};export default message;
//# sourceMappingURL=index.js.map
构建整个组件库

在支持按需引入的同时,如果还需支持完整引入整个组件库。则直接在 rollup 配置里加入一个完整的组件库入口

rollup.config.js 最终配置
// rollup.config.js
const fs = require('fs-extra');
const path = require('path');
const pkg = require("../package.json")import vue from 'rollup-plugin-vue2'
import postcss from 'rollup-plugin-postcss'
import postcssScss from 'postcss-scss'
import autoprefixer from 'autoprefixer'
import base64 from 'postcss-base64'
import url from 'rollup-plugin-url'import progress from 'rollup-plugin-progress'
import filesize from 'rollup-plugin-filesize';function isDir(dir) {return fs.lstatSync(dir).isDirectory();
}const packages = {};
const dir = path.join(__dirname, '../packages');
const files = fs.readdirSync(dir);
files.forEach(file => {const absolutePath = path.join(dir, file);if (isDir(absolutePath)) {packages[file] =`packages/${file}/index.js`;}
});
const allScript = `${pkg.name}.all`
packages[allScript] = `packages/index.js`;function createRollupConfig (file, name) {const config = {input: file,output: {file: name === allScript ? `lib/index.js` : `lib/${name}/index.js`,format: 'es',name: name,sourcemap: true},plugins: [vue(),postcss({extract: true,parser: postcssScss,plugins: [base64({extensions: ['.png', '.jpeg'],root: './packages/',}),autoprefixer({ add: true }),]}),url({limit: 10 * 1024,//include: ['.svg']}),progress(),filesize()]}return config
}const buildPackages = []
for (let name in packages) {const file = packages[name]buildPackages.push(createRollupConfig(file, name))
}export default buildPackages;

产出的构建目录:

lib├─message│      index.js|      index.css|      index.js.map├─pay│      index.js|      index.css|      index.js.map├─share│      index.js|      index.css|      index.js.mapindex.js  //完整组件库,包含所有组件index.cssindex.js.map

到这里构建部分完成,下一步,将构建后的lib目录发布到 npm:

  1. 修改package.json version字段与上次不一样(如: 0.1.2),否则会提交失败
  2. 修改package.json main字段为: lib/index.js
  3. 发布:执行 npm publish
按需引入组件

组件库发布后,我们转入业务项目npm 安装组件库,如:

npm i qw-ui

安装完成后,在项目node_modules文件夹下可以找到名为_qw-ui@0.1.1@qw-ui,即我们刚才发布的组件库.

  1. 完整引入

    当我们想一次引入整个项目,而非单独引入每次组件时: 修改src/main.js,全局引入整个qw-ui,如:

    import Vue from 'vue'
    import App from './App.vue'
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';import qwui from 'qw-ui'     // 全局引入整个组件库
    import 'qw-ui/lib/index.css' // 全局载入样式Vue.config.productionTip = false
    Vue.use(ElementUI)
    Vue.use(qwui)new Vue({render: h => h(App),
    }).$mount('#app')
  2. 按需引入

    按需引入需要借助 babel-plugin-import,我们可以只引入需要的组件,以达到减小项目体积的目的.

    首先npm install babel-plugin-import --save-dev,然后再项目根目录上新建文件.babelrc.

    vue cli3 直接修改babel.config.js文件:

    // babel.config.js
    module.exports = {presets: ['@vue/app'],plugins: [["import", {"libraryName": "qw-ui","customName": (name) => {return `../lib/${name}/index`;},"style": (name) => {return `${name}.css`;}}]]
    }
    // src/main.js
    import Vue from 'vue'
    import App from './App.vue'
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';import { message } from 'qw-ui'     // 按需引入 message 组件Vue.config.productionTip = false
    Vue.use(ElementUI)
    Vue.use(message)new Vue({render: h => h(App),
    }).$mount('#app')
    

    这时候已经启用了 babel-plugin-import ,插件会帮我们将import { message } from 'qw-ui'转换成 import message from 'qw-ui/lib/message' 的写法。同时自动注入组件样式。

    ~ 运行一下项目~~

私有npm

业务性组件库一般只适合于公司内部,组件或多或少的也涉及到代码安全和商业风险,所以将打包后的组件库发布到私有npm而不是发布到公网上的npm官网相对要安全很多.

私有 npm 仓库可以让我们使用组件就像 npm 官方仓库里的包一样方便。

私有 npm 仓库有以下一些特性:

  • 私有包托管在内部服务器或者单独的服务器上;
  • 可以同步整个官方仓库,也可以只同步需要的;
  • 下载的时候,可以让公共包走公共仓库,私有包走私有仓库;
  • 可以缓存下载过的包;
  • 对于下载,发布,有对应的权限管理。

私有npm的搭建有多种方式,最简单的使用 git 仓库作为私有仓库.

快速搭建和部署私有的 npm 包管理服务也可以使用 verdaccio

对权限、安全性、稳定性有更高要求的可以使用 cnpmjs.org, cnpmjs.org 服务的搭建需要配合数据库使用.

完!

【手牵手】搭建前端组件库(二)相关推荐

  1. 搭建前端组件库(二)

    进阶 组件库按需引入 在目前,所有的组件会被打包进一个文件,组件库是一骨碌加载完所有组件,同时也会打包和加载多余的代码.对于小项目这样没有问题,但是当组件库越来越庞大.丰富,特别是像我们带业务逻辑的非 ...

  2. 全面、详细的前端组件库

    全面.详细的前端组件库 前端组件库 搭建web app常用的样式/组件等收集列表(移动优先) 0. 前端自动化(Workflow) 前端构建工具 Yeoman – a set of tools for ...

  3. 如何使用rollup打包前端组件/库

    如何使用rollup打包前端组件/库 目前主流的前端框架vue和react都采用rollup来打包,为了探索rollup的奥妙,接下来就让我们一步步来探索,并基于rollup搭建一个库打包脚手架,来发 ...

  4. Bootstrap前端组件库+构建管理

    目录 构建管理 Grunt Sass JavaScript Bootstrap作为前端组件库 一些语法 媒体查询 辅助类 栅栏系统 补充 代码示例 媒体查询 网格系统 建立可伸缩的甚至是响应式组件的方 ...

  5. 前端组件库(Element UI)的实现原理:教你如何实现自定义组件库,并打包发布至npm

    前端组件库实现原理 前言 Demo地址 一. 组件库开发流程 1)新建vue项目: 2)编写自定义组件,封装成插件: 3)修改配置项 webpack.config.js: pakage.json: 4 ...

  6. 把游戏里面的 UI 做成前端组件库会怎么样?

    在研究生的时候用 Vue2.0 做过一个守望先锋UI库. 当时很沉迷<守望先锋>,有一天突发奇想:我要把游戏里面的 UI 做成前端组件库会怎么样? 然后就一步步开始做了,最后也算把它给实现 ...

  7. 设计一个前端组件库,需要具备哪些能力?

    大厂技术  高级前端  Node进阶 点击上方 程序员成长指北,关注公众号 回复1,加入高级Node交流群 在研究生的时候用 Vue2.0 做过一个守望先锋UI库. 当时很沉迷<守望先锋> ...

  8. 分享给你一个酷炫的前端组件库,还不用起来?

    fancy-components 一个酷炫的前端组件库 大伙前端都是用什么组件库的呢? 我最近刚发现前端一个很好看.很炫酷的组件库.那就是fancy-components ,简直是"酷炫&q ...

  9. 前端组件库自定义主题切换探索-03-webpack-theme-color-replacer webpack 同时替换多个颜色改造

    接上一篇<前端组件库自定义主题切换探索-02-webpack-theme-color-replacer webpack 的实现逻辑和原理-02> 这篇我们来开始改造,让这个插件最终能达到我 ...

最新文章

  1. 并行多机调度遗传算法调参记录---变异和淘汰哪个更重要?
  2. 我的Android进阶之旅------Android Gusture 手势识别小案例
  3. Bootstrap(七):CSS--图片
  4. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第12篇]椭圆曲线上的群理论是什么
  5. glibc库详解及与POSIX,system V这些库之间关系的说明
  6. android 系统(6)---Android ADB 命令大全
  7. 插值和空间分析(二)_变异函数分析(R语言)
  8. (转)《精通比特币》原码分析: rpc_block
  9. Android——实现全国省市区地区选择
  10. paho.mqtt.c的Linux编译与交叉编译
  11. 一款功能强大、高颜值、官方出品的Redis可视化工具
  12. 从算法原理到应用部署!微信「扫一扫识物」 的背后技术揭秘
  13. mybatis多表联合查询
  14. [poi-tl]转换html内容到word
  15. idea中整合redis中出现 Error creating bean with name ‘com.sxt.redis.RedisApplicationTests‘:
  16. Microsoft Help Viewer help查看器所需的内容文件缺失或者损坏 解决办法
  17. Hexo+NexT 如何取消下划线
  18. 苹果笔记本用户使用Mac版本微博软件Maipo,如何添加账户与高级授权?
  19. ❤️熬夜爆肝十万字❤️Java最简单最全入门基础知识(一)(小白必备--推荐小白收藏)❤️
  20. 2012北京航空航天大学考研机试真题

热门文章

  1. 【自嗨笔记#5】2020 最新B站视频下载方法
  2. 怎么一键发布 Web 墨卡托投影坐标系的卫星地图
  3. 字节跳动薪酬体系曝光,我承认我酸了
  4. 【论文笔记2】基于梯形面积估计的大规模网络异常检测几何面积分析新技术
  5. 被华为任正非刷屏的一天,怎么能少了 GitHub 上的这个项目!
  6. SpringBoot 之Profiles
  7. SpringCloud多环境配置Profiles
  8. 如何使用Echarts创建动态K线图
  9. sdk\tools目录下的traceview.bat无法找到
  10. 收到私信问:怕在试用期被辞退!我:......