vue代码分块和懒加载非必要资源文件


Posted in Vue.js onApril 11, 2022

前端开发中,随着业务和页面增加,以组件为基本单位的结构下,组件数量会增长极快,为了优化我们会很显然地想要进行一些工作:

  • 代码分块
  • 懒加载非必要资源文件

非必要资源,指的首次渲染出某页面所不必要的资源,如因为用户操作才出现的图片、弹窗等。

代码分块和懒加载在页面层面具有极大的优化作用,用户很可能只是浏览dashboard页面,可能根本就不会去看详情等页面,那我们就不必将详情页面的代码和dashboard页面代码混在一起,用户看某个页面时只加载那个页面对应的资源即可,可以较大地提升用户体验。本文就在Vue工程下如何在组件层面配置代码分块和懒加载进行讲解。

本文在@vue/cli 3以上版本。

懒加载组件

一般来说,Vue中使用某组件过程大致如下:

<script>
// Home.vue
import HelloWorld from '@/components/HelloWorld.vue'
export default {
  components: {
    HelloWorld,
  },
}
</script>

这是我们最熟悉的方式了,我们在访问Home.vue时,Webpack为我们保证了HelloWorld.vue一定是存在的,这是由依赖关系决定的(Home.vue依赖于HelloWorld.vue)。

这很正常对吧,但是如果HelloWorld.vue是非必要资源呢,比如需要用户点击一个按钮才会出现的弹窗或者是默认隐藏的内容,只当某些条件触发时才出现的页面区域呢?如果是上述情况,当我们访问Home.vue时显然没必要马上就将HelloWorld.vue请求过来,而且配置方法也及其简单:

<template>
  <div class="home">
    <button @click="() => showHello = true">Hello</button>
    <HelloWorld v-if="showHello" />
  </div>
</template>
<script>
// Home.vue
export default {
  components: {
    HelloWorld: () => import('@/components/HelloWorld.vue'),  // A
  },
  data() {
    return {
      showHello: false,
    }
  },
}
</script>

只需像A行一样简单处理一下即可一举两得:HelloWorld.vue会被打包成独立为单独的js文件,而且只有当我们点击按钮时,这个独立的js文件才会被请求,这样能够减小主代码块的体积。

简单分析一下:import()会返回一个组件Promise,现在基本上所有的打包工具都理解此语法,而且还会触发Webpack的代码分块(Webpack 2之后)。

注意:Vue不会在意某个组件,直到它要被渲染出来。以上例来说,只有当我们触发了按钮,HelloWorld.vue才有了意义。

即使所有组件都可以配置懒加载,但是别滥用,大部分情况下只对非必要资源配置懒加载即可,像上例如果HelloWorld.vue是Home.vue中是一直存在的,那样配置懒加载可能会适得其反,加载了Home.vue对应的js文件后会马上请求HelloWorld.vue对应的js文件,如果HelloWorld.vue对应的js文件比较小,那得到的收益可能不足以抵消一次http请求带来的消耗。

问题与解决方案

组件懒加载虽然好处极多,但仍有缺陷,如上例点击按钮后需等待HelloWorld.vue对应的js文件被请求执行后页面才会做出相应变化,这就涉及到加载状态和错误状态的处理(虽然一般情况下不会有问题,因为都是些小文件,加载极快,但也有例外),所幸Vue也为我们考虑到了这些:

加载中组件

<script>
// Home.vue
import LoadingComponent from '@/components/Loading'
export default {
  components: {
    HelloWorld: () => ({
      component: import('@/components/HelloWorld.vue'),
      loading: LoadingComponent,  // 加载HelloWorld.vue对应js文件中展示
      delay: 300,                 // loading的延迟生效时间
    }),
  },
  data() {
    return {
      showHello: false,
    }
  },
}
</script>

从用户体验方面来说,般来说500ms内的响应时间还不至于失去用户的注意力,所以可以为loading配置一个延迟时间,默认200ms内加载完成不会出现loading,当然也可以像上面一样手动设置一下delay,单位ms。

错误处理组件

<script>
// Home.vue
import ErrorComponent from '@/components/Error'
export default {
  components: {
    HelloWorld: () => ({
      component: import('@/components/HelloWorld.vue'),
      error: ErrorComponent,  // 加载HelloWorld.vue对应js文件失败时展示,如文件不存在
      timeout: 2000,          // 文件加载的超时时间,超出时间未加载完成,会触发ErrorComponent
    }),
  },
  data() {
    return {
      showHello: false,
    }
  },
}
</script>

出现错误的情形主要有以下几点:

  • 网络连接不通 / 服务器错误
  • 文件不存在(特别注意重新部署后之前版本的文件被删除,而用户还未刷新页面)
  • 加载超时(默认是没有超时时间的,不过可以像上面一样通过timeout属性配置,单位ms)

preload 和 prefetch

Vue还为资源文件配置了预加载策略,即使用<link rel="prefetch">和<link rel="preload">策略,在build后的index.html文件中或者开发模式下浏览器的Network面板里可以具体查看。关于两者的具体用法这里就不赘述了,这里说一下两者差异之处:preload的优先级比prefetch的高,一般来说当前页面的必要资源可以使用preload策略,当前页面的非必要资源和其他页面的资源使用prefetch策略。

通过配置资源预加载,浏览器为我们预先预先加载资源,在用户用到某些资源时可以及时响应,可以在提升首次加载性能的同时为用户后续的操作提供良好的体验。

prefetch在Safari中暂时还不支持,所以懒加载在Safari中表现地相对较差。

总结

Vue中使用懒加载和代码分块对产品进行优化,简单实用,但是这其中存在着权衡,如果项目较小,打包文件并不大,则可能不需要进行代码分块和懒加载,毕竟http请求也是挺贵的。

当项目较大时,使用懒加载和代码分块就可以显著地提升性能,但是同样注意那需要由后来的请求弥补的,但所幸目前大部分浏览器都支持资源预加载策略,搭配使用效果更佳。

Vue.js 相关文章推荐
详解vue实现坐标拾取器功能示例
Nov 18 Vue.js
vue实现广告栏上下滚动效果
Nov 26 Vue.js
vue3+typeScript穿梭框的实现示例
Dec 29 Vue.js
基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析
Dec 30 Vue.js
vue调用微信JSDK 扫一扫,相册等需要注意的事项
Jan 03 Vue.js
vue watch监控对象的简单方法示例
Jan 07 Vue.js
Vue 实现可视化拖拽页面编辑器
Feb 01 Vue.js
如何在 Vue 中使用 JSX
Feb 14 Vue.js
vite2.0+vue3移动端项目实战详解
Mar 03 Vue.js
vue点击弹窗自动触发点击事件的解决办法(模拟场景)
May 25 Vue.js
VUE中的v-if与v-show区别介绍
Mar 13 Vue.js
vue/cli 配置动态代理无需重启服务的方法
May 20 Vue.js
vue打包时去掉所有的console.log
三种方式清除vue路由跳转router-link的历史记录
Apr 10 #Vue.js
vue route新窗口跳转页面并且携带与接收参数
Apr 10 #Vue.js
vue实力踩坑之push当前页无效
Apr 10 #Vue.js
vue实现Toast组件轻提示
Apr 10 #Vue.js
vue自定义右键菜单之全局实现
Apr 09 #Vue.js
vue判断按钮是否可以点击
Apr 09 #Vue.js
You might like
PHP:风雨欲来 路在何方?
2006/10/09 PHP
php+mysql不用递归实现的无限级分类实例(非递归)
2014/07/08 PHP
php模拟服务器实现autoindex效果的方法
2015/03/10 PHP
php验证邮箱和ip地址最简单方法汇总
2015/10/30 PHP
php爬取天猫和淘宝商品数据
2018/02/23 PHP
利用PHP内置SERVER开启web服务(本地开发使用)
2020/01/22 PHP
JavaScript中的new的使用方法与注意事项
2007/05/16 Javascript
深入了解javascript中的prototype与继承
2013/04/14 Javascript
用js一次改变多个input的readonly属性值的方法
2014/06/11 Javascript
JQuery 在文档中查找指定name的元素并移除的实现方法
2016/05/19 Javascript
从重置input file标签中看jQuery的 .val() 和 .attr(“value”) 区别
2016/06/12 Javascript
Vue.js学习之计算属性
2017/01/22 Javascript
uploader秒传图片到服务器完整代码
2017/04/22 Javascript
深入理解es6块级作用域的使用
2019/03/28 Javascript
小程序封装wx.request请求并创建接口管理文件的实现
2019/04/29 Javascript
简单通过settimeout看javascript的运行机制
2019/05/10 Javascript
JavaScript变量作用域及内存问题实例分析
2019/06/10 Javascript
vue data恢复初始化数据的实现方法
2019/10/31 Javascript
Python的Django框架中的URL配置与松耦合
2015/07/15 Python
使用matplotlib画散点图的方法
2018/05/25 Python
Python之用户输入的实例
2018/06/22 Python
Python 删除整个文本中的空格,并实现按行显示
2018/07/24 Python
Python实现的批量修改文件后缀名操作示例
2018/12/07 Python
基于pytorch padding=SAME的解决方式
2020/02/18 Python
Django中的模型类设计及展示示例详解
2020/05/29 Python
PyTorch中model.zero_grad()和optimizer.zero_grad()用法
2020/06/24 Python
将不规则的Python多维数组拉平到一维的方法实现
2021/01/11 Python
详解pycharm的python包opencv(cv2)无代码提示问题的解决
2021/01/29 Python
HTML5+CSS设置浮动却没有动反而在中间且错行的问题
2020/05/26 HTML / CSS
购买原创艺术品:Zatista
2019/11/09 全球购物
教师实习自我鉴定
2013/12/13 职场文书
销售部主管岗位职责
2013/12/18 职场文书
安全生产承诺书范文
2014/05/22 职场文书
英语专业求职信
2014/07/08 职场文书
村干部群众路线教育活动对照检查材料
2014/10/01 职场文书
Python+Appium新手教程
2021/04/17 Python