首屏加载优化方案(vue项目)

3,172 阅读6分钟

1.图片压缩

2.图片懒加载

3.异步组件

一般的写法是

<!--App.vue-->
<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
  components: {
    HelloWorld
  }
}
</script>

这种加载方式只要App被导入,就可以在初始加载时,HelloWorld组件就会被导入,使用和加载.但是如果HelloWorld组件在一开始页面渲染时并不需要呢?用户很可能在整个浏览网站的过程中不会使用到该组件.比如弹框组件.

那为什么我们要在应用程序开始时花宝贵的资源来加载组件呢?我们可以应用延迟加载和代码拆分来改进它,延迟加载是在稍后的阶段加载某些内容的技术.

代码拆分是在编译时将一段代码拆分到一个单独的文件中,以便减少应用程序的初始包,从而减轻初始加载.

通过使用动态导入,webpack将理解这种语法,并自动为该模块创建一个单独的文件,该文件将在需要时加载.

原理就是通过import的动态导入,webpack将模块拆分成单独的文件,减少了初始包的大小.

区分静态导入和动态导入

// 静态导入模块
import utils from './utils'
 
// 动态导入
import('./utils').then(utils => {
    // 可以在这里使用utils模块
})

在vue中延迟加载组件,前面的例子可以这样写

<!--App.vue-->
<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
export default {
  components: {
    HelloWorld:()=>import('./components/HelloWorld.vue')
  }
}
</script>

Vue一旦请求渲染将会延迟加载该组件,并且该组件被拆分成一个单独的js文件进行加载,看network.

多出来一个0.js文件,并且这个0.js有一个还是prefetch请求,下面会详细讲到.

现在我们在组件需要渲染时立即加载了,如果是需要用户触发显示的,我们可以加v-if,将组件加载延迟到需要展示时加载.

<!--App.vue-->
<template>
  <div @click='show=true'></div>
  <div id="app">
    <div v-if='show'>
        <HelloWorld msg="Welcome to Your Vue.js App"/>
    </div>    
  </div>
</template>
<script>
export default {
  data(){
    return {
        show: false
    }
  }
  components: {
    HelloWorld:()=>import('./components/HelloWorld.vue')
  }
}
</script>

现在这样写,该组件只有在show为true时才会加载.

用户体验

大多数情况,异步组件的加载速度是很快的,因为他们是从主包中拆分出来的小块代码.但是在弱网情况下加载一个大的模态组件,可能需要一些时间加载和渲染.从用户的角度来看,我们需要给一些反馈来让用户保持注意力,我们可以在加载时使用一个loading组件.可以这样写.

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" @click='show=true'>
    <div v-if='show'>
      <HelloWorld msg="Welcome to Your Vue.js App"/>
    </div>
  </div>
</template>
<script>
import AwesomeSpinner from './components/AwesomeSpinner'
export default {
  data(){
    return {
        show: false
    }
  }
  components: {
    // HelloWorld:()=>import('./components/HelloWorld'),
    HelloWorld:()=> ({
        component: import('./components/HelloWorld'),
        // 异步组件加载时使用的组件
        loading: AwesomeSpinner,
        // 组件加载失败时时使用的组件
        error: AwesomeSpinner,
        // 最长加载时长,如在这个时间内没有加载成功,则显示error组件,默认是无限长
        timeout: 5000
    })
  }
}
</script>

总结

异步组件就是用import异步加载的方式,在组件需要渲染的时候加载和渲染,webpack将异步加载的组件自动拆分成了单独的js模块,减少了初始包的大小,减少了应用的加载时间.同时vue还提供了在组件加载慢时对用户用好的反馈的配置项.

4.Vue-Router路由懒加载(利用webpack的代码分割)

在单页面应用中,我们用vue-router,加载不同的模块

//router.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

import mine from './pages/mine/index'
import main from './pages/main/index'
const routes = [
    { path: '/mine', name:'mine', component: mine },
    { path: '/', name:'main', component: main }
]

export default new VueRouter({
    routes
})

这种引入方式会在页面首次加载时,就把所有的页面都加载过来.

//router.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

// import mine from './pages/mine/index'
// import main from './pages/main/index'
// import login from './pages/login/index'
const routes = [
    { path: '/mine', name:'mine', component: ()=>import(/* webpackChunkName: "mine" */ './pages/mine/index') },
    { path: '/', name:'main', component: ()=>import(/* webpackChunkName: "main" */ './pages/main/index') },
    { path: '/login', name:'login', component: ()=>import(/* webpackChunkName: "login" */ './pages/login/index') }
]

export default new VueRouter({
    routes
})

改写成这种动态加载的方式,webpack会自动进行代码分割,把每个路由下的页面分割成单独的模块,当导航到那个页面时,才会加载这个页面对应的js资源,这样减小了初始资源文件的大小,使网站首次加载速度提高.

虽然这样初始包变小了,但不好的地方是,当页面跳转时才会加载当前页面的资源,会导致loading状态,体验并不好,prefetch就是为了解决这个问题,prefetch表示在浏览器空闲时去加载,这样在切换页面时,资源已经被加载了,会提高页面切换速度.

4.webpack gzip压缩

我们都知道压缩后的文件会变小很多,那在build时,如果把文件压缩,在网络传输时就会因为文件体积变小,而节约传输时间.

配置webpack压缩

// vue.config.js
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
    configureWebpack: {
        plugins: [new CompressionPlugin()]
    }
}

下载compression-webpack-plugin

yarn add compression-webpack-plugin

打包文件

yarn build

在dist目录中可以看到生成了三个文件.js .gzip .map,在控制台可以看到压缩后文件还是小了很多的.

.map文件是为了追踪报错的,打包后的js文件一些变量名已经被替换,空格和换行也已经被去掉,如果执行报错很难追踪到错误代码的位置,.map文件记录了这些信息,当代码执行出错时可以提醒错误位置.如果不想生成.map可以这样配置:

//vue.config.js
module.exports = {
    productionSourceMap: false,
    configureWebpack: {
        ...
    }
}

现在已经打包生成了.gzip文件,nginx需要相应的配置:

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /lijianjian/hello-world/dist;
        index  index.html index.htm;
        gzip_static on;
    }
}

配置完成后,更新nginx配置文件

nginx -s reload

现在浏览器可以加载到gzip的资源了

compression-webpack-plugin还可以有很多其他的配置,像压缩那些类型的文件,多大以上才压缩,详细的看git介绍

当然,解压缩也是需要时间的,但是和大文件压缩后节省的传输时间相比,还是值得的.

5.使用了UI库,按需加载ui组件

6.preload