1409 字
7 分钟
3DCAT 官网首页优化记录-资源优化

优化前后(Chrome Lighthouse)#

PC#

diff-pc

Mobile#

diff-mobile

构建产物#

diff-build

移除无用的导入残留#

人工对代码自底向上进行审查,移除了无用的注释与 Props 传递,从而移除了无用的内容导入,减少构建体积。

例如:子组件不再渲染该图片资源,但由于存在引用传递,依旧会被构建工具打包。

import xxx from "xxx.png";

function Parent() {
  return <Child title={"xxx"} image={xxx} />;
}

function Child({ title, image /* unused */ }) {
  return (
    <div>
      <h1>{title}</h1>

      {/* 历经迭代,组件的构造已时进过迁 ... */}
      {/* <img src={image} /> */}
    </div>
  );
}

自动化工具审查#

此类问题可以利用自动化工具有效解决,例如运用 ESLint 严格校验未使用变量,使用 TS 保证代码的类型安全(由于历史原因无法使用 TS 的项目可以使用 JSDoc + TS Check 替代)。

计划在后续对此项目的迭代规划中将此项列入并作为重点。

但自动化工具毕竟是执行通用规则,难免也会有疏漏,偶尔需要人工辅助介入,那么每次较大的版本改动是否需要执行一次代码审查?

图片优化#

(1)对于网络图片或本地小型图片、图标,设置原生的 loading 属性(但此设置对 base64 编码的图片无效):

<img src="//xxx.png" loading="lazy" />

(2)对于本地图片,使用gatsby-plugin-image转化渲染,一次性解决懒加载、格式转化与体积压缩三大问题,详见:资源优化

百度地图#

由于百度地图的渲染位于首页靠底部区域,虽然可使用async/defer对其 SDK 进行延迟加载,但当该 SDK 脚本初始化时,其内部还会涉及大量的资源或依赖脚本请求,有可能会阻塞浏览器的渲染。

故此将其修改为懒加载模式,借助 IntersectionObserver API 监测元素的可见性,当地图元素出现在浏览器视窗时再去加载与初始化地图。

function BaiduMap(props) {
  const id = props.id;

  useEffect(() => {
    const ele = document.querySelector(`#${id}`);
    if (!ele) return;

    // NOTE: Setting the JSONP callback function
    window.setupBaiduMap = () => initMap(id);

    // NOTE: Making lazy load with IntersectionObserver
    const observerInstance = new IntersectionObserver((entries, observer) => {
      const box = entries[0];
      if (box.isIntersecting) {
        const scriptEle = document.createElement("script");

        scriptEle.src =
          "//api.map.baidu.com/api?v=3.0&ak=xxx&callback=setupBaiduMap";
        scriptEle.setAttribute("async", "true");
        document.head.appendChild(scriptEle);

        observer.unobserve(box.target);
      }
    });

    observerInstance.observe(ele);

    return () => observerInstance.disconnect();
  }, []);

  return <div id={id} style={{ width: "100%", height: "100%" }} />;
}

Graphql 查询优化#

首页的「最新动态」只需要显示最新的 5 条数据,而目前的逻辑是先全量请求(约有 350 条数据),再手动截取出 5 条数据。

# graphql query
{
  data: allContentfulNews {
    nodes {
      slug
      title
      createdAt(formatString: "YYYY-MM-DD HH:mm:ss")
      content {
        content
      }
      newContent {
        newContent
      }
    }
  }
}

这会导致构建之后产生的 JSON 文件体积较大,而其中有 90% 的数据是无用的,对构建速度、网络加载速度等多方面产生影响。

优化方案:限制请求数量即可。

# graphql query
{
-  data: allContentfulNews {
+  data: allContentfulNews(limit: 5) {
    nodes {
      slug
      title
      createdAt(formatString: "YYYY-MM-DD HH:mm:ss")
      content {
        content
      }
      newContent {
        newContent
      }
    }
  }
}

其它优化#

  • 依赖优化:使用 day.js 代替 moment.js 以减少构建体积。
  • SEO 优化:根据建议补充图片的 alt 属性、超链接的 href 属性。
  • 布局抖动优化:根据建议对 img 补充宽高的设置,减少布局抖动所带来的重绘回流与视觉体验。
  • 服务器优化:向运维人员申请启用服务器的 HTTP/2、Gzip 功能

从 gatsby 2 升级到 gatsby 3 出现的问题#

路由导航错误#

问题表现:在新闻页面对新闻数据列表进行分页跳转时,导航到了错误的页面。

问题原因:gatsby 2 在执行导航之前默认会对 pathname 中多余的 / 做去重处理,而 gatsby 3 却移除了此行为。

解决方法:在跳转路由之前先对 pathname 做去重:pathname.replace(/\/+/g, '/')

网站地图(SiteMap)抓取失败#

问题表现:营销部同学反馈网站地图抓取失败。

sitemap

问题原因:经排查,是插件gatsby-plugin-sitemap使用了新的规则去创建 sitemap,新的规则是以文件夹的形式存在,因此访问上图中的路径时出现 403 错误(无权访问该文件夹)。

  1. 旧规则:gatsby-plugin-sitemap直接创建sitemap.xml文件(命名与目录视配置而定)
  2. 新规则:根据搜索引擎(厂商)的要求,每个sitemap-x.xml文件的索引条目不能超过 50000 条,多余的需要拆分到下一个文件,最后再通过一个入口文件(sitemap-index.xml)索引重定向这些拆分后的文件,详见:gatsby-plugin-sitemap

解决方法:重新配置了输出目录,通知营销同学重新上传新路径。

特别注意#

百度不支持索引文件(为了打击非法产业与泛目录类网站),需上传最终含有实际 url 的sitemap-0.xml等文件。

baidu-sitemap-failure

baidu-sitemap-success

总结#

本次协同优化工作,主要针对官网首页以及核心附属页,优化目标集中在以下方面:

  1. 对无用代码、资源文件进行审查删除,减少构建体积
  2. 对图片等富媒体资源做懒加载、格式转换与体积压缩

其它的优化目标属于性能压榨,这些因素对整体性能的影响占比不到 10%。

整体上像是执行了一场比较严格的 code-review,毕竟没有对项目做太多编译构建层面的优化。

计划在下一次的迭代中先对项目的工程化体系进行完善,有效地利用自动化工具作为把守代码质量的第一道关卡。

3DCAT 官网首页优化记录-资源优化
https://www.hzhi.top/posts/project-optimization-3dcat-resource/
作者
Jim的独立博客
发布于
2023-07-25
许可协议
CC BY-NC-SA 4.0