当“移动优先”(mobile-first)的方式逐渐成为一种标准,而不肯定的网络环境因素应该始终是咱们考虑的一点,所以保持让应用程序快速加载变得愈来愈困难。在本系列文章中,我将深刻研究Vue性能优化技术,咱们在 Vue Storefront 中已经使用了这些技术,您也能够在Vue.js应用程序中使用这些技术,使它们可以当即加载并顺利运行。个人目标是使本系列成为关于Vue应用程序性能的完整指南。javascript
本系列的大部分技巧将集中于使咱们的JS包更小。要理解这一点,首先咱们须要理解 Webpack 是如何打包(bundling)咱们全部的文件的。当打包咱们的资源时,Webpack 建立了被成为依赖图(dependency graph)的东西,它是一个基于入口,连接咱们全部文件的图。假设咱们在webpack配置中指定了一个名为 main.js 的文件做为入口点,它将是依赖关系图的根。如今,咱们将在此文件中导入的每一个js模块将成为图中的节点,而且在此节点中导入的每一个模块都将成为其节点。Webpack 正是使用这个依赖关系图来检测输出的包中应该包含哪些文件。输出包只是一个包含依赖关系图中全部模块的 Javascript 文件(或后面的部分将看到多个)。css
咱们能够图解这个过程,像这样:html
如今,当咱们知道打包是如何工做的,很明显咱们的项目越多,初始的 javascript 包体积会变的越大。包太大,下载和解析的时间就会越长,用户过很长时间才能看到有意义的东西。用户等待的时间越长,他/她就越有可能离开咱们的网站。前端
简而言之,更大的bundle = 更少的用户。至少在大多数状况下是这样。vue
所以,当咱们仍然须要添加新特性和改进应用程序时,咱们如何可以减小包的大小?答案很容易-延迟加载和代码分割。java
顾名思义,延迟加载就是延迟加载应用程序的某些部分。换句话说,只有在咱们真正须要的时候才加载它们。代码分割就是将应用程序分割成这些延迟加载的块。webpack
在大多数状况下,您不须要在用户访问您的网站后当即从Javascript文件中得到全部代码。即便咱们的应用程序中会有3个不一样的路由,无论用户最终会在哪一个路由上,他/她老是须要下载、解析和执行文件中三个路由的代码,即使是只须要访问一个路由。多么浪费时间和精力!git
延迟加载容许咱们分割包(split the bundle),并只提供所须要的部分,这样用户就不会浪费时间下载和解析不被使用的代码。github
要查看咱们的网站实际使用了多少JavaScript代码,咱们能够到开发者工具 -> cmd+shift+p -> type coverage -> 点击 'record'。如今咱们应该可以看到实际使用了多少下载的代码。web
全部标记为红色的东西都是当前路由上不须要的,能够延迟加载。若是您正在使用源码映射(source maps ),您能够单击此列表中的任何文件,查看它的哪些部分没有被调用。咱们能够看到,即便是 vuejs.org 也有很大的改进空间。
经过延迟加载适当的组件和库,咱们设法将 Vue Storefront 的文件大小减小了60%!
好了,咱们知道什么是延迟加载,它很是有用。
如今来看看如何在Vue.js应用程序中使用它。
咱们能够轻松地用 webpack dynamic imports 加载应用程序的某些部分。让咱们看看它们是如何工做的,以及它们与常规导入有何不一样。
若是咱们将以这样的标准方式导入JS模块:
// main.js import ModuleA from './module_a.js' ModuleA.doStuff()
它将做为 main.js 的一个节点添加到依赖关系图中,并与之打包在一块儿。
可是,若是咱们仅在某些状况下须要 ModuleA,例如对用户交互的响应,那该怎么办呢?将这个模块与初始文件打包在一块儿不是一个好主意,由于可能根本不须要它。咱们须要一种方法来告诉应用程序什么时候应该下载这段代码。
这就是动态导入能够帮助咱们的地方!如今看看这个例子:
//main.js const getModuleA = () => import('./module_a.js') // 做为对某些用户交互的响应调用 getModuleA() .then({ doStuff } => doStuff())
让咱们快速看看这里发生了什么:
咱们没有直接导入 module_a.js,而是建立了一个返回 import() 函数的函数。如今webpack将动态导入模块的内容打包到一个单独的文件中,除非函数被调用,不然不会导入也不会下载文件。在稍后的代码中,咱们下载了这段可选代码,做为对某些特定用户交互的响应(如路由更改或单击)。
经过动态导入,咱们基本上隔离了将添加到依赖关系图中的给定节点(在本例中是 module_a),并在肯定须要时下载这一部分(这意味着咱们还切断了在module_a.js中导入的模块)。
让咱们看另外一个例子,它将更好地说明这种机制。
假设咱们有4个文件: main.js, module_a.js、module_b.js 和 module_c.js。要了解动态导入的工做原理,咱们只须要 main 和 module_a 的源代码:
//main.js import ModuleB from './mobile_b.js' const getModuleA = () => import('./module_a.js') getModuleA() .then({ doStuff } => doStuff() ) //module_a.js import ModuleC from './module_c.js'
经过使 module_a 成为一个动态导入的模块,咱们把 module_a 及其全部的子模块从依赖图切割成一部分。当 module_a 被动态导入时,它与其中导入的模块一块儿加载。换句话说,咱们只是为依赖关系图建立了一个新的入口点。
这就是咱们的依赖关系图和文件包在给定设置下的样子。
咱们知道什么是延迟加载,以及为何须要它。如今看看如何在Vue应用程序中使用它。
好消息是它很是简单,咱们能够延迟加载整个SFC(译者注:Vue Single-File Component -- 单文件组件)以及它的css和html,语法与以前如出一辙!
const lazyComponent = () => import('Component.vue')
这就是你所须要的! 如今只有在请求时才会下载组件。 如下是调用Vue组件动态加载的最经常使用方法:
const lazyComponent = () => import('Component.vue') lazyComponent()
<template> <div> <lazy-component /> </div> </template> <script> const lazyComponent = () => import('Component.vue') export default { components: { lazyComponent } } </script>
请注意,只有当组件被请求要在模板中渲染时,才会调用 lazyComponent 函数。
例以下面的代码:
<lazy-component v-if="false" />
这样不会动态导入组件,由于它并无添加到DOM中(可是当值变为true时就会动态导入,这是一种延迟加载Vue组件的好方法)。
延迟加载是提升web应用程序性能并减小其大小的最佳方法之一。咱们学习了如何使用Vue组件的延迟加载。在本系列的下一部分中,我将向您展现如何使用 Vue-router 和 async 路由来分割Vue应用程序代码。
若是对你有帮助,请关注【前端技能解锁】: