【优化】h5项目优化实践
项目架构
本 h5 项目分为两个子项目:服务端项目和客户端项目。
服务端的职责是响应用户对页面的请求,服务端拿到客户端生成的 ejs 文件,注入数据后响应。使用 NestJS 搭建,采用 EJS 模板引擎。
客户端的职责是生成 ejs 模板供服务端使用,采用 webpack 多入口方式打包,每个页面都是单独的入口和出口,最终都被编译为 ejs 文件。这样的模式下一个页面可以根据具体需求使用不同的技术框架实现,现有的页面实现方式有两种:SEO 要求较高的页面,使用 zepto + html 实现;无 SEO 要求的页面使用 Vue + html 实现。
页面展现速度优化方案
减少首屏 http 请求数量
并发的 http 请求会抢占带宽,并且浏览器有 http 最大并发数量限制(一般在 4-10 之间)。
减少小尺寸 chunk 数量
尺寸较小的 chunk(flexible.js、css)可以直接打包到 ejs 文件中。
观察下面这个 chunk 的 http 请求,可以看到建立连接(16ms)比下载内容(3ms)更耗时,像这样的 chunk 完全可以直接打包到页面中,而不是通过额外的 http 请求加载。
图片懒加载
vue 项目使用 vue-lazyload@1.3.3 实现图片懒加载。
精灵图
合并小图片。
减少页面响应数据尺寸
减少页面响应数据的尺寸可以减少浏览器下载页面数据的时间,从而提高页面展现速度。
模块动态导入
直接导入的模块会被打包到 vendor.js 中(得看具体 webpack 配置),导致单一 chunk 体积过大,而且通常情况下这个很大的 chunk 覆盖率并不高。
通过动态导入的方式可以让 webpack 在编译时将这个模块分离出来成为单独的 chunk,并只在被用到的时候加载(通过 http 请求)。
- 组件懒加载
// 直接导入
import Address from "@/components/Address";
// 动态导入
const Address = () =>
import(/* webpackChunkName: "c.Address" */ "@/components/Address");
需要注意,未动态判断组件的情况下,会直接加载组件。
<template>
<!-- 直接加载组件 -->
<Address />
<!-- isShowAddress 变为true后加载组件 -->
<Address v-if="isShowAddress" />
</template>
- 模块懒加载
// 直接导入
import Http from "@/services/Http";
// 动态导入
const { default: Http } = await import(
/* webpackChunkName: "s.Http" */ "@/services/Http"
);
提高服务端响应速度
减少服务端的同步接口请求
在服务端发送同步接口请求,会提高页面响应时间,因此尽可能将同步请求放到客户端去实现。
静态化 SSR
浏览器侧优化
dns 预解析
<head>
<!--告诉浏览器开启 DNS 预解析-->
<meta http-equiv="x-dns-prefetch-control" content="on" />
<!--添加需要预解析的域名-->
<link rel="dns-prefetch" href="https://xxx" />
</head>
预加载页面
<head>
<link rel="prefetch" href="https://main.m.taobao.com/search/index.html" />
</head>