侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

将Vue组件库更换为按需加载的方法步骤

前端  /  管理员 发布于 6年前   313

本文介绍了将Vue组件库更换为按需加载的方法步骤,分享给大家,具体如下:

按需加载DEMO仓库地址

背景

我司前端团队拥有一套支撑公司业务系统的UI组件库,经过多次迭代后,组件库体积非常庞大。

组件库依赖在npm上管理,组件库以项目根目录的 index.js 作为出口导出,文件中导入了项目中所有的组件,并提供组件安装方法。

index.js

import Button from "./button";import Table from "./table";import MusicPlayer from "./musicPlayer";import utils from "../utils"import * as directive from "../directive";import * as filters from "../filters";const components = {  Button,  Table,  MusicPlayer}const install = (Vue) => {  Object.keys(components).forEach(component => Vue.use(component));    // 此处继续完成一些服务的挂载}if (typeof window !== 'undefined' && window.Vue) { install(Vue, true);}export default {  install,  ...components}

组件库并不导出编译完成后的依赖文件,业务系统使用时,安装依赖并导入,就能注册组件。

import JRUI from 'jr-ui';Vue.use(JRUI);

组件库的编译是交由业务系统的编译服务顺带编译的。

即组件库项目本身不会编译,仅作为组件导出。node_module 就像一个免费的云盘,用于存储组件库代码。

因为经业务系统编译,在业务系统中。组件库代码能够和本地文件一样,直接调试。而且非常简单粗暴,并不需要做一些依赖导出的额外配置。

但也存在缺点

  • 组件库中无法使用更为特殊的代码

vue-cli会静态编译在 node_module 引用的 .vue 文件,但不会编译 node_module 中的其他文件,一旦组件库代码存在特殊的语法扩展(JSX),或者特殊的语言(TypeScript)。此时项目启动会运行失败。

  • 组件库中使用 webpack 的特殊变量将不起效

组件库中的 webpack 配置不会被业务系统去执行,所以组件库中的路径别名等属性无法使用

  • 组件库依赖每次都是全量加载

index.js 本身就是全量的组件导入,所以即使业务系统只使用了部分组件, index.js 也会将所有的组件文件(图片资源,依赖)都打包进去,依赖体积总是全量大小的。

业务系统并不存在只使用一两个组件的情况,每个业务系统都需要绝大部分组件。
几乎每个项目都会使用比如 按钮,输入框,下拉选项,表格 等常见基础组件。
只有部分组件仅在少数特殊业务线使用,例如 富文本编辑器,音乐播放器。

组件分类

为了解决上述问题,及完成按需引入的效果。提供两种组件导出方式,全量导出,基础导出。
将组件导出分为两种类型。基础组件,按需引入组件。
按需引入组件的评定标准为:

  • 较少业务系统使用
  • 组件中包含体积较大或资源文件较多的第三方依赖
  • 未被其他组件内部引用

全量导出模式导出全部组件,基础导出仅导出基础组件。在需要使用按需引入组件时,需要自行引入对应组件。

调整为按需引入

参考 element-ui 的导出方案,组件库导出的组件依赖,要提供每个组件单独打包的依赖文件。

全量导出 index.js 文件无需改动,在 index.js 同级目录增加新文件 base.js,用于导出基础组件。

base.js

import Button from "./Button";import Table from "./table";const components = {  Button,  Table}const install = (Vue) => {  Object.keys(components).forEach(component => Vue.use(component));}export default {  install,  ...components}

修改组件库脚手架工具,增加额外打包配置。用于编译组件文件,输出编译后的依赖。

vue.config.js

const devConfig = require('./build/config.dev');const buildConfig = require('./build/config.build');module.exports = process.env.NODE_ENV === 'development' ? devConfig : buildConfig;

config.build.js

const fs = require('fs');const path = require('path');const join = path.join;// 获取基于当前路径的目标文件const resolve = (dir) => path.join(__dirname, '../', dir);/** * @desc 大写转横杠 * @param {*} str */function upperCasetoLine(str) { let temp = str.replace(/[A-Z]/g, function (match) {  return "-" + match.toLowerCase(); }); if (temp.slice(0, 1) === '-') {  temp = temp.slice(1); } return temp;}/*** @desc 获取组件入口* @param {String} path*/function getComponentEntries(path) {  let files = fs.readdirSync(resolve(path));  const componentEntries = files.reduce((fileObj, item) => {   // 文件路径   const itemPath = join(path, item);   // 在文件夹中   const isDir = fs.statSync(itemPath).isDirectory();   const [name, suffix] = item.split('.');     // 文件中的入口文件   if (isDir) {    fileObj[upperCasetoLine(item)] = resolve(join(itemPath, 'index.js'))   }   // 文件夹外的入口文件   else if (suffix === "js") {    fileObj[name] = resolve(`${itemPath}`);   }   return fileObj  }, {});    return componentEntries;}const buildConfig = { // 输出文件目录 outputDir: resolve('lib'), // webpack配置 configureWebpack: {  // 入口文件  entry: getComponentEntries('src/components'),  // 输出配置  output: {   // 文件名称   filename: '[name]/index.js',   // 构建依赖类型   libraryTarget: 'umd',   // 库中被导出的项   libraryExport: 'default',   // 引用时的依赖名   library: 'jr-ui',  } }, css: {  sourceMap: true,  extract: {   filename: '[name]/style.css'  } }, chainWebpack: config => {  config.resolve.alias   .set("@", resolve("src"))   .set("@assets", resolve("src/assets"))   .set("@images", resolve("src/assets/images"))   .set("@themes", resolve("src/themes"))   .set("@views", resolve("src/views"))   .set("@utils", resolve("src/utils"))   .set("@mixins", resolve("src/mixins"))   .set("jr-ui", resolve("src/components/index.js")); }}module.exports = buildConfig;

此时我们的 npm run build 命令,执行的便是以上这段 webpack 配置。

配置中,会寻找组件目录的所有入口文件。对每个入口文件根据设置进行编译输出到指定路径。

configureWebpack: {  // 入口文件  entry: getComponentEntries('src/components'),  // 输出配置  output: {   // 文件名称   filename: '[name]/index.js',   // 输出依赖类型   libraryTarget: 'umd',   // 库中被导出的项   libraryExport: 'default',   // 引用时的依赖名   library: 'jr-ui',  }},css: {  sourceMap: true,  extract: {   filename: '[name]/style.css'  }}

function getComponentEntries(path) {  let files = fs.readdirSync(resolve(path));  const componentEntries = files.reduce((fileObj, item) => {   // 文件路径   const itemPath = join(path, item);   // 在文件夹中   const isDir = fs.statSync(itemPath).isDirectory();   const [name, suffix] = item.split('.');     // 文件中的入口文件   if (isDir) {    fileObj[upperCasetoLine(item)] = resolve(join(itemPath, 'index.js'))   }   // 文件夹外的入口文件   else if (suffix === "js") {    fileObj[name] = resolve(`${itemPath}`);   }   return fileObj;  }, {});    return componentEntries;}

项目中的组件目录为如下,配置将会将每个组件打包编译导出到 lib 中

components             组件文件目录│             │― button             │  │― button.vue         button组件│  └─ index.js          button组件导出文件││― input             │  │― input.vue          input组件│  └─ index.js          input组件导出文件││― musicPlayer│  │― musicPlayer.vue       musicPlayer组件│  └─ index.js          musicPlayer组件导出文件││ base.js             基础组件的导出文件└─ index.js            所有组件的导出文件lib                编译后的文件目录│             │― button             │  │― style.css          button组件依赖样式│  └─ index.js          button组件依赖文件││― input             │  │― style.css          input组件依赖样式│  └─ index.js          input组件依赖文件││― music-player│  │― style.css          musicPlayer组件依赖样式│  └─ index.js          musicPlayer组件依赖文件││― base             │  │― style.css          基础组件依赖样式│  └─ index.js          基础组件依赖文件│└─ index               │― style.css          所有组件依赖样式  └─ index.js          所有组件依赖文件

获取组件全部入口时,对入口名称做驼峰转横杠处理 upperCasetoLine,是因为 babel-plugin-import 在按需引入时,如组件名称为驼峰命名,路径会转换为横杠分隔。

例如业务系统引入

import { MusicPlayer } from "jr-ui"// 转化为var MusicPlayer = require('jr-ui/lib/music-player');require('jr-ui/lib/music-player/style.css');

因为组件库命名约定,组件文件夹命名大小写并不以横杠隔开。但为了让 babel-plugin-import 正确运行,所以此处对每个文件的入口文件名称做了转换处理。

如不经过方法转换名称,也可以配置 babel.config.js 中的plugin-import配置 camel2DashComponentName 为 false,来禁用名称转换。

babel-plugin-import路径命名issue

业务系统使用时

全量导出默认导出全部组件

// 全量导出import JRUI from "jr-ui";import "jr-ui/lib/index/index.css";Vue.use(JRUI);

基础导出仅导出基础组件,如需要使用额外组件,需要安装 babel-plugin-import 插件且配置 babel.config.js 来完成导入语句的转换

npm i babel-plugin-import -D

业务系统――babel.config.js配置

module.exports = { presets: ["@vue/app", ["@babel/preset-env", { "modules": false }]], plugins: [  [   "import",   {    "libraryName": "jr-ui",    "style": (name) => {      return `${name}/style.css`;    }   }  ] ]}

基础导出

import JRUI_base from "jr-ui/lib/base";import "jr-ui/lib/base/index.css";Vue.use(JRUI_base);// 按需使用额外引入的组件import { MusicPlayer } from "jr-ui";Vue.use(MusicPlayer);

业务系统中调试组件库代码

如果仍然想调试组件库代码,在引入组件时,直接引入组件库依赖内的 components 下的组件导出文件并覆盖安装。就能调试目标组件。

import button from "jr-ui/src/components/button";Vue.use(button);

优化效果

在组件库较大的情况下,优化效果非常明显。在使用基础组件时,体积小了一兆。而且还减少了很多组件内不必要的第三方依赖文件资源。

案例仓库地址,如有疑问和错误的地方,欢迎大家提问或指出。
祝你有个快乐的劳动节假期 :)
Have a nice day.

参考资料

vue-cli执行解析
babel-plugin-import

 到此这篇关于将Vue组件库更换为按需加载的方法步骤的文章就介绍到这了,更多相关Vue组件库更换为按需加载内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


  • 上一条:
    Vue SSR 即时编译技术的实现
    下一条:
    基于vue3.0.1beta搭建仿京东的电商H5项目
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 使用 Alpine.js 排序插件对元素进行排序(0个评论)
    • 在js中使用jszip + file-saver实现批量下载OSS文件功能示例(0个评论)
    • 在vue中实现父页面按钮显示子组件中的el-dialog效果(0个评论)
    • 使用mock-server实现模拟接口对接流程步骤(0个评论)
    • vue项目打包程序实现把项目打包成一个exe可执行程序(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-03
    • 2018-04
    • 2018-05
    • 2018-06
    • 2018-09
    • 2018-11
    • 2018-12
    • 2019-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2021-04
    • 2021-05
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客