前端优化首屏加载速度

执行npm run build,将打包代码部署上线后访问项目,会发现表现很糟糕,页面会出现长时间的空白等待,这是无法忍受的性能问题,迫切需要解决。

1、路由懒加载。

原来的路由引入组件

import Index from @/views/index.vue;
{
    
    
	path: '/'
	name: 'index'
	component: Index
}

现在引入路由(vue异步组件)

import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router)
 {
    
    
      path: "/",
      name: "index",
      component: resolve => require(["@/views/Index"], resolve)
}

ES 提出的import方法(常用)
const HelloWorld = ()=>import(‘需要加载的模块地址’)

import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router)
const HelloWorld = ()=>import("@/components/HelloWorld")
export default new Router({
    
    
  routes: [
    {
    
    
      path: '/',
      name: 'HelloWorld',
      component:HelloWorld
    }
  ]
})

2.组件懒加载

原来组件中的写法:

<template>
	<div>
		<span></span>
		<One-com></One-com>
	</div>
</template>

<script>
import One from './one';
export default{
    
    
	components:{
    
    
		"One-com": One,
	},
	data(){
    
    
		return{
    
    
			num: 0
		}
	}
}
</script>

const 方法

<template>
  <div class="hello">
  <One-com></One-com>
  1111
  </div>
</template>

<script>
const One = ()=>import("./one");
export default {
    
    
  components:{
    
    
    "One-com":One
  },
  data () {
    
    
    return {
    
    
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

异步方法:

<template>
  <div class="hello">
  <One-com></One-com>
  1111
  </div>
</template>

<script>
export default {
    
    
  components:{
    
    
    "One-com":resolve=>(['./one'],resolve)
  },
  data () {
    
    
    return {
    
    
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

3.服务器开启gzip。此步的优化效果最显著

第1步 先在vue-config.js中配置开启gzip。

// 安装插件
npm i --save-dev compression-webpack-plugin
 
// 在vue-config.js 中加入
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const productionGzipExtensions = ['js', 'css'];
const isProduction = process.env.NODE_ENV === 'production';
 
.....
module.exports = {
    
    
....
 configureWebpack: config => {
    
    
  if (isProduction) {
    
    
   config.plugins.push(new CompressionWebpackPlugin({
    
    
    algorithm: 'gzip',
    test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
    threshold: 10240,
    minRatio: 0.8
   }))
  }
 }
}

第2步 WEB服务器开启gzip。这里以我的nginx为例。

gzip  on;
gzip_types text/plain application/x-javascript application/javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;

4.启用cdn加速。

用Gzip已把文件的大小减少了三分之二了。如果还不能满足,把那些不太可能改动的代码或者库分离出来,继续减小单个chunk-vendors,然后通过CDN进行加速加载资源。
(对vue、vuex、vue-router、vue-moment采用cdn引入,此外客户端还可以引入highlight的cdn,但管理端不需要。因此,需要两份不同的模板html,配置分别如下:)

(1)、vue.config.js 在上一步的基础上继续加入

config.externals的配置,如下:
configureWebpack: config => {
    
    
    if (isProduction) {
    
    
      config.plugins.push(
        new CompressionWebpackPlugin({
    
    
          algorithm: "gzip",
          test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"),
          threshold: 10240,
          minRatio: 0.8
        })
      );
 
      config.externals = {
    
    
        vue: "Vue",
        "vue-router": "VueRouter"
      };
    }
  }

(2)、在原来所有引入vue、vue-router的地方,全部屏蔽或删除。

//原来对vue、vue-router的引用全部注释掉。
//涉及所有引用的文件,只要有引入就注释掉。
 
// import Vue from "vue";
// import Router from "vue-router";
 
//vue-router的非cdn引用
//Vue.use(Router);
 

(3)、在代码中用vue-router的时候,用VueRouter。

//cdn 引入vue-router时,源码抛出的变量是:VueRouter
console.log(VueRouter);
Vue.use(VueRouter);
 
//Vue.use(Router); 继续像原来一样用Router就会报错。

预渲染

以上方案解决的问题是缩小js资源体积以便加快加载速度,这样的方案在网络良好的情况下首屏渲染的速度已经够快了,但是终归讲,渲染依赖于js加载完成后的执行逻辑,而且这样的方式不利于SEO。那么进一步提高首屏加载的方案还有两个,一个是预渲染,一个是SSR,即服务端渲染,后者的方案较为复杂,我会在以后的文章中进行分析,服务端渲染的方式相比预渲染,最主要的优势是可以动态拼接数据,作为文档的一部分返回,从而实现更友好的SEO和动态分享等功能。

预渲染依赖一个prerender-spa-plugin插件,首先要在webpack.prod.conf.js中引入该插件,如下

const PrerenderSPAPlugin = require('prerender-spa-plugin')

然后,在plugins中添加以下插件配置:

new PrerenderSPAPlugin(

      path.join(__dirname, '../nginx/blog'),
      ['/'],
      {
    
    
        //在一定时间后再捕获页面信息,使得页面数据信息加载完成
          captureAfterTime: 50000,
          //忽略打包错误
          ignoreJSErrors: true,
          phantomOptions: '--web-security=false',
          maxAttempts: 10,
        }
)

经过这样配置以后,打包生成的index.html就包含了预渲染的dom结构,因此首屏渲染速度会得到更大提升。但是这里要注意一个问题,异步加载的路由打包后的chunk文件被插入了head标签中,并且带有一个async属性,如下:

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>Blog - SilentPort</title>
  <link href="/static/css/client.6b5a982c3673872dbaa1a8891279d36d.css" rel="stylesheet">
  <script type="text/javascript" charset="utf-8" async="" src="/static/js/3.c925dfc72043d1d1d5ac.js"></script>
</head>

而运行时的manifest文件则位于body的底部,由于async会导致加载和渲染后续文档元素的过程和当前script脚本的加载与执行并行进行(异步),因此会导致该script脚本先于manifest执行,这会产生一个webpackJsonp is not defined错误。因此在部署之前这里需要手动将async改成defer,后者在加载后续文档元素的过程中也会和当前script脚本的加载并行进行(异步),但是当前script脚本的执行要在所有元素解析完成之后,DOMContentLoaded事件触发之前完成,这样就保证了脚本后于manifest执行。

参考文章:https://www.jianshu.com/p/da46f410156a?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

猜你喜欢

转载自blog.csdn.net/weixin_39854011/article/details/111822108