import按需加载资源优化实践

最近在做项目的首屏优化工作, 提起首屏优化会有很多方式,但是对于如何减小静态资源的加载体积少之又少, 这次记录下在项目中优化的过程.

背景

我们的项目是C端项目, 页面内容是强依赖后端接口数据, 后端接口不返回数据页面不会展示任何内容,(体验的事情,暂时先不谈😭)

页面组件结构

首页模版中用了一些组件,有第三方的,有自己写的

简单介绍下各个组件

  • XxxGuider:一个自定义的组件,展示一些业务相关的引导
  • loading:整个页面的loading
  • cb-ui-render:一个历史悠久的组件(也是后面重点优化的对象), 源码已经没人维护, (我有一次翻到源码,做了一次构建,构建出来的产物功能已经不全了😭), 页面的展示就是依靠它
  • popup, error, lottery,Risk-Control-Part: 自定义的功能性组件

cb-ui-render

关于cb-ui-render的组件要多说一些

在工程中的某个位置, 代码长这样,cb-ui-render是这一坨代码导出其中的一个组件

在项目中这样使用

javascript 复制代码
import CbPlugIn from '@phoenix'
Vue.use(CbPlugIn)

然后在模版中才能试用,否则汇报组件未定义的警告. 写过Vue插件的朋友应该大致猜到了, 这个 CbPlugIn 是一个install函数或者带有install 方法的对象, install 中执行类似这样一行代码 Vue.component('CbUiRender', cb-ui-render组件)

cb-ui-render 接收 uiData 这样的 props 属性, 由 uiData 的数据结构渲染界面

uiData 的数据结构长这样 uiData 是基于接口返回的数据生成的 整体是一个对象结构, 最外层是页面级的数据, elements 是页面中各个组件的数据, 其中的type 属性是组件名称, props 属性是组件用到的数据, on 属性是事件

这样的数据结构传入到 uiData 后, 会根据这样的数据结构生成一个vue的组件对象, 该组件对象的模板(template)属性字符串中用到的组件标签就是 uiData 中的各个 type 关于cb-ui-render 组件内部逻辑比较复杂,这里不在赘述

看下代码执行截图吧, 这里注册 CbUiRender , xs 是对应的组件对象 经过一系列的执行之后,这里生成一个组件对象, 看下 template 属性

这里箭头指的就是 uiData 中的 type

项目中自定义组件

在这样的前提下,我们想要用 cb-ui-render 渲染,就要提前把对应的组件通过Vue.component 注册(这里是为了不用的业务应用做了分开的注册)

然后在首页导入并执行 Vue.use

webpack 分包

由于这个 '@phoenix' 和自定义的 import { bocComponent } from '@/component/uiGadget/components/bocComponent.js' 会比较大,如果不用webpack做分包处理会达到默认的vendor

所以在webpack中这样配置下

这些包就被分到独立的 vendor 中,在浏览器中间加载看看

要等到这些vendor 加载完才会调用接口,获取数据渲染页面,严重影响页面渲染

开始优化

先看之前的 app.vue

cb-ui-render 这个组件依赖接口数据, 可以不在最开始写在模版中, 可以先写一个挂载的dom节点, 利用Vue组件实例挂载的方式等到接口获取到数据再挂载到dom上

具体代码如下:

模版中加一个 idrender_container 的 div

原本注册组件的逻辑由

javascript 复制代码
// 引入渲染器组件
import CbPlugIn from '@phoenix'
Vue.use(CbPlugIn)

// 注册自定义2c组件
import { bocComponent } from '@/component/uiGadget/components/bocComponent.js'
Vue.use(bocComponent)

改成用 import() 函数导入的方式, import 函数可以写在js的逻辑中, 在部署上线之后,每 import 一个js文件,就会发送一个js的请求

同时利用 Promise.all 和接口做并发请求, 这样在获取到数据,获取到两个js资源后,再注册组件,我给封装到一个函数中

处理组件挂载的逻辑,上图中的 this.mount

这里可以用Vue.extend,也可以用new Vue(), 用Vue.extend扩展出一个构造函数,在用这个构造函数生成一个Vue实例,然后挂载到dom中

bocComponent.perf.js 文件改造如下

(修改前) 这样写有个问题: 网络加载的资源中是包含所有组件的js, 体积庞大

(修改后)

index.perf.js 文件改造如下

(修改前)

(修改后)

目标实现接口中返回哪个组件就加载哪个组件, 即所谓的按需加载. 通过 import 函数在配合 /* webpackChunkName: 'xxx'*/ (这样改了之后,要把 webpack 原来 optimization 的分包逻辑去掉)

即可实现组件的按需加载,同时还能减小首屏加载js资源的个数和体积. 部署到线上再看资源的加载情况,

由修改之前的 phoenixSrcVendor(100kb), cxui-components-vendor(228kb), cxui-boc-components-vendor(387kb), cxui-other-components-vendor(104kb) 4个 bundle 减小到现在的 @phoenix(100kb), bocComponent(779b), components(73.5kb)

同时页面中用到了 cxui-title-new ,cxui-banner-new, cxui-nav-menu-new三个组件, 在网络请求中也只加载这三个组件

各个bundle体积也明显减小

总结

利用 import 函数,灵活调整导入组件位置, 同时利用webpack的分包机制, 实现组件的按需导入,减小原来bundle的体积, 加快页面的加载速度

相关推荐
Moment1 小时前
从方案到原理,带你从零到一实现一个 前端白屏 检测的 SDK ☺️☺️☺️
前端·javascript·面试
鱼樱前端1 小时前
Vue3 + TypeScript 整合 MeScroll.js 组件
前端·vue.js
拉不动的猪2 小时前
刷刷题29
前端·vue.js·面试
野生的程序媛2 小时前
重生之我在学Vue--第5天 Vue 3 路由管理(Vue Router)
前端·javascript·vue.js
codingandsleeping2 小时前
前端工程化之模块化
前端·javascript
CodeCraft Studio2 小时前
报表控件stimulsoft操作:使用 Angular 应用程序的报告查看器组件
前端·javascript·angular.js
阿丽塔~2 小时前
面试题之vue和react的异同
前端·vue.js·react.js·面试
烛阴3 小时前
JavaScript 性能提升秘籍:WeakMap 和 WeakSet 你用对了吗?
前端·javascript
yuren_xia4 小时前
eclipse创建maven web项目
前端·eclipse·maven
鱼樱前端4 小时前
Vue 2 与 Vue 3 语法区别完整对比
前端·javascript·vue.js