美文网首页
vue多页面首页加载优化

vue多页面首页加载优化

作者: SilentPort | 来源:发表于2018-10-17 09:48 被阅读0次

    还是以自己的多页面博客为例,执行npm run build,将打包代码部署上线后访问项目,会发现表现很糟糕,页面会出现长时间的空白等待。通过下图可以看到,总加载时长达到将近12s,这是无法忍受的性能问题,迫切需要解决。

    客户端加载示意图:

    管理端加载示意图

    引入CDN

    vuevuexvue-routervue-moment采用cdn引入,此外客户端还可以引入highlight的cdn,但管理端不需要。因此,需要两份不同的模板html,配置分别如下:

    tpl/index.html

    tpl/admin.html

    externals: {
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'vuex': 'Vuex',
        'vue-moment': 'VueMoment',
        'highlight.js': 'hljs',
    },
    

    代码分割

    在webpack.prod.conf.js中,修改CommonsChunkPlugin的配置,如下:

    new webpack.optimize.CommonsChunkPlugin({
          name: 'vendor',
          minChunks (module) {
            return (
    
              module.resource &&
              /\.js$/.test(module.resource) &&
              module.resource.indexOf(
                path.join(__dirname, '../node_modules')
              ) === 0 && module.resource.indexOf('mavon-editor') < 0
               && module.resource.indexOf('marked') < 0
            )
          }
    }),
    

    异步加载路由

    对于上面提到的问题,如果把路由引入方式改为异步引入,webpack打包的时候会单独打包异步文件作为一个新的chunk,并且在需要时才会在页面中加载。以管理端为例,修改路由引入方式为异步引入,如下:

    const Catagory = () => import('../pages/Catagory');
    const Avator = () => import('../pages/Avator')
    const Comment = () => import('../pages/Comment')
    const Detail = () => import('../pages/Detail')
    const Article = () => import('../pages/Article')
    

    gzip压缩

        gzip_static on;
        gzip_min_length  5k;
        gzip_buffers     4 16k;
        gzip_comp_level 4;
        gzip_types       text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php;
        gzip_vary on;
        keepalive_timeout  65;
    

    其中gzip_static开启后,nginx就会读取预先压缩的gz文件,这样就可以减少每次请求进行gzip压缩的CPU资源消耗,这也就是为什么需要webpack对文件作压缩的原因。所有配置的解释可以参考Nginx Gzip模块启用和配置指令详解_nginx

    缓存加速

    预渲染

    以上方案解决的问题是缩小js资源体积以便加快加载速度,这样的方案在网络良好的情况下首屏渲染的速度已经够快了,但是终归讲,渲染依赖于js加载完成后的执行逻辑,而且这样的方式不利于SEO。那么进一步提高首屏加载的方案还有两个,一个是预渲染,一个是SSR,即服务端渲染,后者的方案较为复杂,我会在以后的文章中进行分析,服务端渲染的方式相比预渲染,最主要的优势是可以动态拼接数据,作为文档的一部分返回,从而实现更友好的SEO和动态分享等功能。我的博客因为没有这些需求,并且考虑到服务器的状况(单核1GB),不想给服务器增加负载,因此不考虑SSR,将采用预渲染的方式进一步加快首屏加载。
    预渲染依赖一个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执行。
    优化到这里,部署上线,就可以体验飞一般的首屏体验了。

    相关文章

      网友评论

          本文标题:vue多页面首页加载优化

          本文链接:https://www.haomeiwen.com/subject/vbjlzftx.html