浅谈自己知道的首屏加载时间的优化策略

    |     2020年4月17日   |   web前端技术, 优化   |     0 条评论   |    1074

SPA应用已成为主流,Angular、React、Vue三大框架已经占据前端开发的大半江山,但随着SPA的流行,弊端也随着出现,不仅首屏加载慢,而且不利于SEO,所以vue全家桶或者react全家桶,都是推荐通过服务端渲染来实现路由的。

下面让我们来了解何为服务端渲染

服务端渲染

1.概念

当用户第一次请求页面时,由服务器把需要的组件或页面渲染成 HTML 字符串,然后把它返回给客户端。客户端拿到手的,是可以直接渲染然后呈现给用户的 HTML 内容,不需要为了生成 DOM 内容自己再去跑一遍 JS 代码。

使用服务端渲染的网站,即“所见即所得”,页面上呈现的内容,我们在 html 源文件里也能找到。

2.利弊

好处:

首屏渲染快;

利于SEO;

可以生成缓存片段,生成静态化文件、节能(对比客户端渲染的耗电)

坏处:

用户体验较差;

不容易维护,通常前端改了部分html或者css,后端也需要修改。

3.和客户端渲染对比

无论是客户端渲染,还是服务端渲染,本质是一样的,都是字符串的拼接,将数据渲染进一些固定格式的html代码中形成最终的html展示在用户页面上。

因为字符串的拼接必然会损耗一些性能资源。如果在服务器端渲染,那么消耗的就是server端的性能。

如果是在客户端渲染,常见的手段,比如是直接生成DOM插入到html 中,或者是使用一些前端的模板引擎等。他们初次渲染的原理大多是将原html中的数据标记(例如{{text}})替换。

为什么使用服务端渲染

简单总结起来就是两点:

1、首屏加载快相比于加载单页应用,我只需要加载当前页面的内容,而不需要像 React 或者 Vue 一样加载全部的 js 文件

2、SEO 优化对于单页应用,搜索引擎并不能收录到 ajax 爬取数据之后然后再动态 js 渲染出来的页面。

 

最近我在使用vue全家桶开发一个移动端的页面,经过一个半月项目接近完工,处于优化的阶段。
用过前端框架的都知道,spa(单页面应用)的一个最大的缺点就是首屏的加载时间比较长。
缩小首屏载时间是一个重要的优化项,总结来主要有以下几种方式:

  1. 尽可能的缩小webpack或者其他打包工具生成的包的大小
  1. 使用服务端渲染的方式
  1. 使用预渲染的方式
  1. 使用gzip减小网络传输的流量大小
  1. 按照页面或者组件分块懒加载

1. 缩小webpack或者其他打包工具生成的包的大小

为了做到这一点,需要做到尽可能的减少生产环境下依赖的库数量,尽可能的按需引用,减少无用代码占的空间。
我刚开始优化的时候,就不知道从何处优化起,而且根本不知道生成的包中哪个依赖占据着空间,我还一度挨个删去库引用,来看哪个库占用的空间最多。 后来才知道有名叫:webpack-bundle-analyzer的分析工具,接下来我顺带总结一下这个包的使用姿势。
: 首先

npm install --save-dev webpack-bundle-analyzer

然后在webpack.prod.conf.js中配置:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [
new BundleAnalyzerPlugin(
     {
          analyzerMode: 'server',
          analyzerHost: '127.0.0.1',
          analyzerPort: 8888, // 运行后的端口号
          reportFilename: 'report.html',
          defaultSizes: 'parsed',
          openAnalyzer: true,
          generateStatsFile: false,
          statsFilename: 'stats.json',
          statsOptions: null,
          logLevel: 'info'
        }
     ),
]

配置就完成了,正常npm run build 结束后,就会自动打开一个打包生成文件的模块组成图在默认浏览器中,图中面积大的就是占据空间大的模块。

微信截图_20200415133730

例如上图中,我打包后vue模块占据的空间最大,可以根据这张图去做优化,不会再感到优化无从下手了。

另外再记录一个我在使用element-ui时遇到的包过大的坑,如果在开发时,将element-ui全局引入,打包后的vendor包大小至少700kb以上,相当庞大,然后我就进行了局部应用。
我的main.js文件局部代码如下

import {
  Autocomplete,
  Checkbox
  ……
} from 'element-ui'
Vue.use(Autocomplete);
Vue.use(Checkbox);

结果打包后包大小没有发生任何变化,一直找不到问题。后来发现官方文档上还需要安装babel-plugin-component插件才能使局部引用有效,以后看文档一定要细心才行。

2. 使用服务端渲染的方式

这个服务端渲染不同于后端渲染,服务端渲染只是把当前的前端框架中的一部分js代码放到服务器上渲染,加载到浏览器上的html就不是一个空页面,这样可以减少首页的白屏时间,同时提高被搜索引擎检索的机会。
但是这个服务端渲染有不少的局限,例如它的服务端必须依靠node服务器,不进行服务端渲染方式的只需要一个普通的静态服务器就可以了。还有,vue官方的ssr配置异常的复杂,需要花不少的时间,踩不少的坑,如果开发时使用的vue-cli的话,改用服务端渲染会很麻烦。如果必须要使用服务端渲染的话,最好刚开始就使用基于vue的nuxt.js脚手架去开发,会减去繁琐的配置过程。

3. 使用预渲染的方式

这个预渲染的方式简单来说就是在正常打包时,会预先运行一次js代码,将一部分静态的页面直接渲染成html写在生成的index.html中,这种方式在加载完index.html后,就会有界面展示出来,无需等待加载js代码后再去渲染,所以这种方式也可以显著的减少首屏加载时间,也可以提高被搜索引擎检索的机会,同时预渲染的配置很简单,容易上手。
缺点是在需要预渲染的页面较多时,build打包的时间会十分漫长。
预渲染的工具有这些:

prerender-spa-plugin
react-snap
snapshotify
presite

这里还有这几个预渲染插件的各种比较

我比较喜欢预渲染这种优化方式,很简单有效,几乎不需要什么配置。这几种插件的基本原理都是本地运行指定的js代码,然后将空头浏览器渲染出的页面写入指定的h5文件。
但是我自己在做项目的时候,出现了各种各样的问题。在打包时报出各种各样的错误,解决了一个又出一个,把这几个插件都试了一遍,依然没有成功预编译出一个满意的页面效果,当然这是我个人的问题,与这几个轮子没有关系。

最后,我想出了一种“土”办法,就用自己的浏览器去预渲染页面。
在浏览器上打开需要预渲染的页面,然后点击右键选择另存为,将文件保存下来,就得到了“预渲染”的html文件。
如果觉得里面的css代码量太大,推荐使用chrome的一个插件 css used, 下载安装之后,在开发者工具中的element中,与style选项并排的就有一个css used选项,点击后就会加载出这个页面用到的css界面,过滤掉了没有用到的css代码,将有用的css代码替换掉原本html里面的css代码即可。
最后,需要将打包生成的js和css代码的路径添加到html里面(就像打包生成的index.html一样),这样,在这个html加载完成后,就可以显示一个预渲染的页面了,等到依赖的js和css加载完成后,会有新的代码覆盖掉预渲染的页面。
我的这种“土”办法实属无奈,但依旧有效,成功的将首屏加载时间缩短了50%。用这种方法也可以自己制作一个骨架预渲染界面,在等待加载js和css时,界面上只显示一个页面的大体框架,比全白屏的交互体验要好的多。

4.使用gzip减小网络传输的流量大小

gzip是GNUzip的缩写,最早用于UNIX系统的文件压缩。HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术,web服务器和客户端(浏览器)必须共同支持gzip。目前主流的浏览器,Chrome,firefox,IE等都支持该协议。常见的服务器如Apache,Nginx,IIS同样支持gzip。使用gzip可以将原静态文件压缩到30%,效果很明显,对于优化首屏加载时间非常适合。
这种优化实现特别简单,只需要配置一下自己使用的服务器就可以了。
以我使用的nginx服务器的配置为例:

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    proxy_buffering on;
开启gzip
	gzip on;
	# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
	gzip_min_length 1k;
	# gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间
	gzip_comp_level 2;
	# 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
	gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml;
	# 是否在http header中添加Vary: Accept-Encoding,建议开启
	gzip_vary on;
	# 禁用IE 6 gzip
	gzip_disable "MSIE [1-6]\.";
	server {
        listen       80;
        server_name  localhost;
        location /{
            alias /;
            proxy_connect_timeout 1; 
            proxy_send_timeout 30; 
            proxy_read_timeout 60;
            # 这里反向代理到本地的开发服务器上
            proxy_pass http://localhost:8080/;
         }
    }
}

这样就开启了gzip。

5.按照页面或者组件分块懒加载

这种优化,就是将每个组件的js代码独立出来,在使用到这个组件时,才向服务器请求文件,并且请求过一次后就会缓存下来,再次使用到这个组件时,就会使用缓存,不再发送请求。
配置很简单,只需要在vue-router中添加一些简单的配置即可。

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router);

export default new Router({
  mode: 'history',
  linkActiveClass: 'router-link-active',
  routes: [
    {
      path: '/',
      // 这里只需要把原来从外部引入的组件换成以下的语句就可以了
      component: resolve => require(['../components/(你的组件)'], resolve)
    },
  ]
})

其他地方不需要进行任何修改,打包后就会发现js文件数量比原来不分块加载的多了不少。

以上就是我知道或者用过的针对单页面应用的首屏加载时间优化方法,如果还有别的方法,欢迎指出和讨论。

 

更多优化 :https://www.cnblogs.com/mianbaodaxia/p/10751453.html

转载请注明来源:浅谈自己知道的首屏加载时间的优化策略
回复 取消