hexo个人网站优化探索

>> 原文链接

Contents


前言


1. hexo 是什么?

hexo 是一个为了不依赖于后端进行界面实时数据查询展示而设计的网站开发工具。比如之前曾使用 Node.js 作为后台开发过一个博客网站,自己实现后台逻辑的话需要考虑数据库存储、前后端交互、后端 Server 部署啥的。整个流程比较繁杂,在初期可以作为前端开发者个人建站学习的一种方式。hexo 简化了这一流程,它将数据存储和数据获取这两方面都通过编译构建然后本地化集成到前端静态资源里。一个例子就是博客网站通常需要翻页功能来获取博客文章,传统开发方式下,获取下一页这个操作由前端脚本发起,并由后端 Server 处理请求并返回,但是使用 hexo 之后这整个过程都是在本地一次完成的,hexo 将所有静态资源在本地建立了索引。

使用 hexo 通常写手只需要关注 markdown 格式文章的编写,其余的网站编译、构建和发布的流程都可以交由框架进行处理,所有的网站内容均会被打包成静态的 html/css/js 文件。hexo 支持自定义插件,也有一个插件社区,如果写手同时具备前端能力的话也可以发布自己的插件到社区里进行开源共享。

2. 何为优化?

我们通常所讲的性能高低可能侧重于对网站运行速度快慢的评估,其包括静态资源及脚本获取的速度和网站UI界面是否运行流畅。其实广义上的优化应包括:网站性能优化、网站可访性优化、网站SEO优化、网站最佳实践等。

性能优化指标


1. 整体运行性能

  • FCP (First Contentful Paint):从用户开始发起网站请求到浏览器第一次开始渲染网站数据的所用时长。其中提及的第一次开始渲染的网站数据包含网页的文字、图片、HTML DOM 结构等,而不包含位于 iframe 中的网页数据。该指标通常用于衡量本地和服务器首次建立网络通讯的速度。

  • TTI (Time To Interactive):从用户开始导航至网站到页面变为完全可交互所花费的时间。网站可交互的衡量标准就是:网站展示了实际可用的内容、界面上可见元素的网页事件已经被成功绑定(比如点击、拖动等事件)、用户和页面交互的反馈时间低于 50 ms。

  • SI (Speed Index):衡量页面加载过程中内容可视化显示的速度。通俗来讲就是网站界面元素的绘制和呈现速度,如果使用 lighthouse 测量工具的话它会捕获浏览器中处于加载中的页面的多个图片帧,然后计算帧之间的视觉渲染进度。

  • TBT (Total Blocking Time):衡量从页面首次开始渲染(FCP)之后到页面实际可交互(TTI)的时间。通常我们访问一个网站时网站整体呈现后,有一段较短的时间我们不能和界面进行交互,比如鼠标点击、键盘按键等,这段时间浏览器在进行脚本及样式的加载和执行。

  • LCP (Largest Contentful Paint):测量视口中最大的内容元素何绘制到屏幕所需的时间。通常包含这个元素的下载、解析和渲染整个过程。

  • CLS (Cumulative Layout Shift):一个衡量网站加载时整体布局抖动情况的数值指标。如果一个网站在加载过程中用户界面多次抖动和闪烁的话会可能引起用户的轻度不适,因此应该尽量减少网站的重排和重绘次数。

2. 网站可访问性


  
    Document title
    
  
  
    
    

Page title

header

Section heading

text info

Sub-section heading

texgt info

footer
  • 界面元素的 id 唯一性。
  • img 标签的 alt 属性声明。它指定了替代文本,用于在图像无法显示或者用户禁用图像显示时,代替图像显示在浏览器中的内容。
  • form 元素内部声明 label 标签以让读屏器正确工作。
  • iframe 元素声明 title 属性来描述其内部内容以便于读屏器工作。
  • aria 无障碍属性和标签的使用,相关参考 >> aria reference
  • input[type=image]、object 标签添加 alt 属性声明:


Annual report.

  • 需要使用 tab 按键聚焦特性的元素可以声明 tabindex 属性,当我们按 tab 键时焦点会依次切换。并且根据键盘序列导航的顺序,值为 0 、非法值、或者没有 tabindex 值的元素应该放置在 tabindex 值为正值的元素后面:
1) tabindex=负值 (通常是tabindex=“-1”),表示元素是可聚焦的,但是不能通过键盘导航来访问到该元素,用JS做页面小组件内部键盘导航的时候非常有用。
2) tabindex="0" ,表示元素是可聚焦的,并且可以通过键盘导航来聚焦到该元素,它的相对顺序是当前处于的DOM结构来决定的。
3) tabindex=正值,表示元素是可聚焦的,并且可以通过键盘导航来访问到该元素;它的相对顺序按照tabindex 的数值递增而滞后获焦。如果多个元素拥有相同的 tabindex,它们的相对顺序按照他们在当前DOM中的先后顺序决定。
  • table 元素中正确使用 thscope 让行表头和列表头与其数据域一一对应:
My marathon training log
Week Total miles Longest run
1 14 5
2 16 6
  • video 元素指定 track文本字幕资源以方便听障人士使用(需要有字幕资源文件):

  • li 列表标签放在容器组件 ulol 中使用。
  • heading 标签严格按照升序声明,配合 section 或其它元素(例如p标签)正确反映界面内容结构:

Page title

Section Heading

Sub-section Heading

  • 使用 指定网站字符集编码。
  • img 元素引用的图片资源长宽比应该和 img 当前应用的长宽比相同,不然可能造成图片扭曲。
  • 添加 以防止浏览界面渲染异常。

3. 网站是否应用了最佳实践策略

> 1) 使用 target="_blank" 链接如果没有声明 rel="noopener noreferrer" 存在安全风险。

当页面链接至使用 target="_blank" 的另一个页面时,新页面将与旧页面在同一个进程上运行。如果新页面正在执行开销极大的 JavaScript,旧页面性能可能会受影响。并且新的页面可以通过 window.opener 访问旧的窗口对象,比如它可以使用 window.opener.location = url 将旧页面导航至不同的网址。

> 2) 检查浏览器端控制台是否有告警和错误提示,通过指示定位问题并解决。

> 3) http 和 https 协议地址不混用

浏览器已经逐渐开始禁止不用协议资源的混用,比如使用 http 协议的 web 服务器加载 https 协议开头的资源,因此可能出现以下几种情况:

  • 加载了混合内容,但会出现警告;
  • 不加载混合内容,直接会显示空白内容;
  • 在加载混合内容之前,会出现类似是否“显示”,或存在不安全风险而被“阻止”的提示!

应该考虑以下方式进行优化:

  • 将站点加载的部分协议混用外部资源放入自己的服务器进行托管;
  • 对于部署了 https 的网站,在网页声明 将 http 请求转换成 https 请求;
  • 对于部署了 https 的网站,在服务器端添加请求首部:header("Content-Security-Policy: upgrade-insecure-requests")也可以达到一样的效果;
  • 对于同时支持 http 和 https 访问的网站,考虑使用相对协议,而不直接明文指定协议:

> 4) 避免使用 AppCache

AppCache已被废弃 考虑使用service worker的Cache API,

> 5) 避免使用 document.write()

对于网速较慢(2G、3G或较慢的WLAN)的用户,外部脚本通过document.write()动态注入会使页面内容的显示延迟数十秒。

> 6) 避免使用 mutation events

以下mutation events会损害性能,在DOM事件规范中已经弃用:

  • DOMAttrModified
  • DOMAttributeNameChanged
  • DOMCharacterDataModified
  • DOMElementNameChanged
  • DOMNodeInserted
  • DOMNodeInsertedIntoDocument
  • DOMNodeRemoved
  • DOMNodeRemovedFromDocument
  • DOMSubtreeModified

建议使用 MutationObserver 替代

> 7) 避免使用 Web SQL

建议替换为IndexedDB

> 8) 避免加载过于庞大的 DOM 树

大型的DOM树会以多种方式降低页面性能:

  • 网络效率和负载性能,如果你的服务器发送一个大的DOM树,你可能会运送大量不必要的字节。这也可能会减慢页面加载时间,因为浏览器可能会解析许多没有显示在屏幕上的节点。
  • 运行时性能。当用户和脚本与页面交互时,浏览器必须不断重新计算节点的位置和样式。一个大的DOM树与复杂的样式规则相结合可能会严重减慢渲染速度。
  • 内存性能。如果使用通用查询选择器(例如,document.querySelectorAll('li') 您可能会无意中将引用存储到大量的节点),这可能会压倒用户设备的内存功能。

一个最佳的DOM树:

  • 总共少于1500个节点。
  • 最大深度为32个节点。
  • 没有超过60个子节点的父节点。
  • 一般来说,只需要在需要时寻找创建DOM节点的方法,并在不再需要时将其销毁。

> 9) 允许用户粘贴密码

密码粘贴提高了安全性,因为它使用户能够使用密码管理器。密码管理员通常为用户生成强密码,安全地存储密码,然后在用户需要登录时自动将其粘贴到密码字段中。
删除阻止用户粘贴到密码字段的代码。使用事件断点中的Clipboard paste来打断点,可以快速找到阻止粘贴密码的代码。比如下列这种阻止粘贴密码的代码:

var input = document.querySelector('input');
input.addEventListener('paste', (e) => {
  e.preventDefault();
});

4. 网站搜索引擎优化SEO

User-agent: *
Allow: /
Disallow: /wp-admin/
Disallow: /wp-includes/
Disallow: /wp-content/plugins/
Disallow: /?r=*
  • 向搜索引擎提交网站地图 sitemap.xml,xml格式的文本就是专门拿来给电脑进行阅读的语,而 sitemap.xml就是搜寻引擎利用这个规范,让网站主可以使用它来制作一个包含了网站内所有网页的目录档案,提供给搜寻引擎的爬虫阅读。就像是一个地图一样,让搜寻引擎可以知道网站内到底有些什么网页。



  
  
    https://nojsja.github.io/blogs/2019/10/26/63567fa4.html/
    
    2021-04-29T10:02:04.853Z
    
  
  
  
    https://nojsja.github.io/blogs/2020/03/26/7507699.html/
    
    2021-04-29T10:01:30.661Z
    
  



性能测试工具 lighthouse


以上提到的性能监测指标通过 lighthouse 网站性能监测工具可以自动化分析和生成性能测试结果数据,较新版本的 chrome 和 采用 chromium 架构的 edge 浏览器都已经自带了,较低版本的 chrome 浏览器可以通过在商店搜索插件安装。安装后使用 F12 打开控制台,切换到 lighthouse 一栏即可直接使用了:

如图,可以自行决定勾选测试项目和针对测试平台(桌面/移动端),最后点击生成报告即可开始运行自动化测试任务,并在测试完成后打开一个分析结果页面:

lighthouse

结果界面:

lighthouse-test

至此我们就能对网站的整体性能进行一些评估了,上图中的PerformanceAccessibilityBest Practices、和 SEO 依次对应上文我们提及的网站整体性能、网站可访问性、网站最佳实践、搜索引擎SEO优化等指标。我们可以点击每一个具体项目来查看测试工具给出的优化建议:

image

测试结果很大程度上取决于你的 http 静态资源服务器的资源加载速度,比如在不使用代理的情况下,使用 github pages 服务来托管静态资源会比使用国内的 gitee pages 托管服务稍慢,而且可能出现部分资源加载失败的问题。因此国内用户可以使用 gitee pages 来替代 github pages,不过 gitee 非付费用户没有代码自动构建部署功能,需要使用下文提到的 github action 来进行自动化登录并触发构建和部署。

注意: 某些浏览器上安装的插件会影响测试结果,因为插件可能会发起请求加载其它脚本啥的。这种情况下可以直接使用 npm 包管理器全局安装 npm install -g lighthouse,然后使用命令行启动测试流程:lighthouse https://nojsja.gitee.io/blogs --view --preset=desktop --output-path='/home/nojsja/Desktop/lighthouse.html'。最终会根据指定的地址生成一个可直接浏览器测试结果网页文件 lighthouse.html,可以直接打开进行性能排查。

基于 hexo 框架的网站优化


之前写的一篇文章 《前端性能优化技巧详解(1)》,详细的描述了前端性能优化的一些方面,这篇文章不会再罗列每一点,只会对博客中实际应用的优化手段进行说明,大致被划分成这几个方面:

  1. 优化资源加载时间
  2. 优化界面运行性能
  3. 网站最佳实践
  4. 网站 SEO 优化

1. 优化资源加载时间

常见的加载时间优化方式包含以下:

  • 提高网页资源并行加载能力
  • 延迟加载不必要的外部资源
  • 减少碎片化的外部资源请求,小文件做合并
  • 增加网站带宽

➣ 使用 defer/async 异步下载 script 脚本资源

HTML在解析时遇到声明的`; return script; }, injectionType)

被注入的用于监听待加载图片元素是否进入可视区域以进行动态加载的部分代码,使用了 IntersectionObserver API 而不是 window.onscroll 事件的方式,前者具有更好的性能,由浏览器统一监听所有元素位置信息更改并分发滚动事件结果:


(function() {
  /* avoid garbage collection */
  window.hexoLoadingImages = window.hexoLoadingImages || {};

  function query(selector) {
    return document.querySelectorAll(selector);
  }
  
  /* registry listener */
  if (window.IntersectionObserver) {
  
    var observer = new IntersectionObserver(function (entries) {

      entries.forEach(function (entry) {
        // in view port
        if (entry.isIntersecting) {
          observer.unobserve(entry.target);

          // proxy image
          var img = new Image();
          var imgId = "_img_" + Math.random();
          window.hexoLoadingImages[imgId] = img;

          img.onload = function() {
            entry.target.src = entry.target.getAttribute('data-src');
            window.hexoLoadingImages[imgId] = null;
          };
          img.onerror = function() {
            window.hexoLoadingImages[imgId] = null;
          }

          entry.target.src = entry.target.getAttribute('data-loading');
          img.src = entry.target.getAttribute('data-src');

        }
      });
    });
    
    query('img[lazyload]').forEach(function (item) {
      observer.observe(item);
    });
  
  } else {
  /* fallback */
    query('img[lazyload]').forEach(function (img) {
      img.src = img.getAttribute('data-src');
    });
  
  }
}).bind(window)();

➣ 使用 IntersectionObserver API 懒加载其它资源

IntersectionObserver API由于性能更好已经在我的博客中作为一种主要的资源懒加载方式,我还使用它来优化博客评论组件 Valine 的加载。一般评论组件都位于博客文章的最下方,因此刚载入文章页面时完全没有必要进行评论组件的资源加载,可以考虑使用 IntersectionObserver 监听评论组件是否进入视口,进入后再使用 async 异步脚本下载并回调执行评论系统初始化。

另一方面每篇文章底部的音乐播放器 Aplayer 也使用了类似的加载策略,可以说优化效果屡试不爽!

➣ 使用 CDN 加载外部依赖脚本

CDN 即内容分发网络。CDN 服务商将静态资源缓存到遍布全国的高性能加速节点上,当用户访问相应的业务资源时,CDN系统能够实时地根据网络流量和各节点的连接负载状况、到用户的距离和响应时间 等综合信息将用户的请求重新导向离用户最近的服务节点上,使内容能够传输的更快,更加稳定。可以提升首次请求的响应能力。

博客中一些公用外部库比如 BootstrapjQuery 都是使用的外部 CDN 资源地址,一方面可以减小当前主站的网页带宽消耗,另一方面 CDN 也能提供一些资源下载加速。

➣ 使用 Aplayer 替代 iframe 加载网易云音乐

博客之前的版本会在文章界面的底部嵌入一个网易云音乐自己的播放器,这个播放器其实是一个 iframe 像这样:


iframe 加载的时候会加载一堆东西,虽然可以通过 lazy 属性来进行懒加载,不过iframe 也有很多缺点:

  • iframe会阻塞主页面的onload事件
  • iframe和主页面共享HTTP连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载
  • iframe不利于网页布局
  • iframe对移动端不友好
  • iframe的反复重新加载可能导致一些浏览器的内存泄露
  • iframe中的数据传输复杂
  • iframe不利于SEO

新版本将 iframe 播放器换成了 Aplayer 并且把自己喜欢的一个歌曲列表上传到了另一个 gitee pages 仓库 进行静态托管,可以通过以下方式在博客底部加载一个自定义歌曲列表:

var ap = new APlayer({
  container: document.getElementById('aplayer'),
  theme: '#e9e9e9',
  audio: [{
    name: '存在信号',
    artist: 'AcuticNotes',
    url: 'https://nojsja.gitee.io/static-resources/audio/life-signal.mp3',
    cover: 'https://nojsja.gitee.io/static-resources/audio/life-signal.jpg'
    
  },
  {
    name: '遺サレタ場所/斜光',
    artist: '岡部啓一',
    url: 'https://nojsja.gitee.io/static-resources/audio/%E6%96%9C%E5%85%89.mp3',
    cover: 'https://nojsja.gitee.io/static-resources/audio/%E6%96%9C%E5%85%89.jpg'
  }]
});

预览图:

aplayer

2. 优化界面运行性能

➣ 优化页面的回流和重绘情况

1)概念

回流(重排,reflow)和重绘(repaint)是浏览器渲染网页必不可少的一个过程,回流主要HTML渲染过程中元素空间位置和大小改变引起的 DOM 树重新渲染,而重绘是由于节点的样式属性发生改变,并不会影响空间布局。从性能而言回流的性能消耗大,而且容易产生级联效应,即一个正常 DOM 树的流布局中,一个元素发生回流后,该元素位置之后的元素全部都会发生回流并重新渲染,重绘相对性能消耗更小。

2)怎样有效判断界面的回流和重绘情况?

其实一般基于 chromium 架构浏览器都附带一个网页开发工具 Devtools,但可以说绝大多数前端开发者都没有认真了解过这个工具的具体用途,只是把它用作简单的 log调试、网页请求追踪和样式调试这些基础功能。回流和重绘也是可以通过它来进行可视化度量的:F12打开 Devtools,找到右上角三个点的折叠按钮依次打开 -> More Tools(更多工具) -> Rendering (渲染) - 勾选前两项 Paint Flashing (高亮重绘区域) 和 Layout Shift Regions (高亮回流区域),现在重新回到你打开的页面进行操作,操作过程中发生了回流的区域会变成蓝色,发生了重绘的区域会变成绿色,持续时间不长,注意观察。

Devtools

Repaint:

Repaint

Reflow:

Reflow

除了用于可视化界面回流/重绘的情况,Devtools 还有其他一些很实用的功能,比如:Coverage Tools 可以用于分析界面上引入的外部 css/js 脚本内容的使用覆盖率,就是说我们能通过这个工具衡量引入的外部文件的使用情况,使用频次较低的外部资源可以考虑内联或是直接手写实现,提升引入外部资源的性价比

➣ 使用节流和去抖思想优化滚动事件监听

在面对一些需要进行调用控制的函数高频触发场景时,可能有人会对何时使用节流何时使用去抖产生疑问。这里通过一个特性进行简单区分:如果你需要保留短时间内高频触发的最后一次结果时,那么使用去抖函数,如果你需要对函数的调用次数进行限制,以最佳的调用间隔时间保持函数的持续调用而不关心是否是最后一次调用结果时,请使用节流函数。

比如 echarts 图常常需要在窗口 resize 之后重新使用数据渲染,但是直接监听 resize 事件可能导致短时间内渲染函数被触发多次。我们可以使用函数去抖的思想,监听 resize 事件后在监听器函数里获取参数再使用参数调用事先初始化好了的 throttle 函数,保证 resize 过程结束后能触发一次实际的 echarts 重渲染即可。

这里给出节流函数和去抖函数的简单实现:

  /**
    * fnDebounce [去抖函数]
    * @author nojsja
    * @param  {Function} fn [需要被包裹的原始函数逻辑]
    * @param  {Numberl} timeout [延迟时间]
    * @return {Function} [高阶函数]
    */
  var fnDebounce = function(fn, timeout) {
    var time = null;

    return function() {
      if (!time) return time = Date.now();
      if (Date.now() - time >= timeout) {
        time = null;
        return fn.apply(this, [].slice.call(arguments));
      } else {
        time = Date.now();
      }
    };
  };

  /**
    * fnThrottle [节流函数]
    * @author nojsja
    * @param  {Function} fn [需要被包裹的原始函数逻辑]
    * @param  {Numberl} timeout [延迟时间]
    * @return {Function} [高阶函数]
    */
  var fnThrottle = function(fn, timeout) {
    var time = null;

    return function() {
      if (!time) return time = Date.now();
      if ((Date.now() - time) >= timeout) {
        time = null;
        return fn.apply(this, [].slice.call(arguments));
      }
    };
  };

博客中文章右侧的内容导航栏会根据滚动条位置自动切换 fixed 布局和一般流布局,这么做是为了让导航栏在阅读文章过程中也能正常呈现,不会被隐藏到顶部:

  /* 限150ms才能触发一次滚动检测 */
  (window).on('scroll', fnThrottle(function() {
      var rectbase = $$tocBar.getBoundingClientRect();
      if (rectbase.top <= 0) {
        $toc.css('left', left);
        (!$toc.hasClass('toc-fixed')) && $toc.addClass('toc-fixed');
        $toc.hasClass('toc-normal') && $toc.removeClass('toc-normal');
      } else {
        $toc.css('left', '');
        $toc.hasClass('toc-fixed') && $toc.removeClass('toc-fixed');
        (!$toc.hasClass('toc-normal')) && $toc.addClass('toc-normal');
        ($$toc.scrollTop > 0) && ($$toc.scrollTop = 0);
      }
  }, 150));

➣ IntersectionObserver API 的 polyfill 兼容策略

文章中提到 IntersectionObserver API 已经用于博客中各个界面组件的懒加载功能,它的性能更好、功能也更加全面。但是网页开发中我们通常会考虑各个 API 的兼容性,这里可以通过 Can I Use 这个兼容性报告网站进行查看,从下图可知这个 API 的兼容情况还是可以的,桌面端很多较高版本浏览器均已支持:

caniuse

因此为了解决个别低版本浏览器的兼容性问题,这里采用了一种比较极端的处理方式。常规情况下我们需要引入外部 [xxx].polyfill.js (xxx为相应的 API) 来为低版本浏览器添加相应功能,但是对于高版本浏览器自身已经支持了这个 API,却要重复下载 polyfill 库,造成网页请求数和带宽资源的浪费。因此我这里不采用这种方式,因为这个 API 大部分浏览器已经支持,我们默认不使用

➣ 使用 IntersectionObserver 替代原生 onscroll 事件监听

IntersectionObserver 通常用于界面中的一些相交检测场景:

  • 图片懒加载 – 当图片滚动到可见时才进行加载
  • 内容无限滚动 – 用户滚动到接近滚动容器底部时直接加载更多数据,而无需用户操作翻页,给用户一种网页可以无限滚动的错觉
  • 检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况
  • 在用户看见某个区域时执行任务、播放视频

以内容无限滚动为例,古老的相交检测方案就是使用 scroll 事件监听滚动容器,在监听器函数中获取滚动元素的几何属性判断元素是否已经滚动到底部。我们知道scrollTop等属性的获取和设置都会导致页面回流,并且如果界面需要绑定多个监听函数到scroll事件进行类似操作的时候,页面性能会大打折扣:

  /* 滚动监听 */
  onScroll = () => {
    const { 
      scrollTop, scrollHeight, clientHeight
    } = document.querySelector('#target');
    
    /* 已经滚动到底部 */
    // scrollTop(向上滚动的高度);clientHeight(容器可视总高度);scrollHeight(容器的总内容长度)
    if (scrollTop + clientHeight === scrollHeight) { /* do something ... */ }
  }

这里以一个简单实现的图片懒加载功能来介绍下它的使用方式,详细使用可以查看博客:《前端性能优化技巧详解(1)》。

(function lazyload() {

  var imagesToLoad = document.querySelectorAll('image[data-src]');

  function loadImage(image) {
    image.src = image.getAttribute('data-src');
    image.addEventListener('load', function() {
      image.removeAttribute('data-src');
    });
  }

  var intersectionObserver = new IntersectionObserver(function(items, observer) {
    items.forEach(function(item) {
      /* 所有属性:
        item.boundingClientRect - 目标元素的几何边界信息
        item.intersectionRatio - 相交比 intersectionRect/boundingClientRect
        item.intersectionRect -  描述根和目标元素的相交区域
        item.isIntersecting - true(相交开始),false(相交结束)
        item.rootBounds - 描述根元素
        item.target - 目标元素
        item.time - 时间原点(网页在窗口加载完成时的时间点)到交叉被触发的时间的时间戳
      */
      if (item.isIntersecting) {
        loadImage(item.target);
        observer.unobserve(item.target);
      }
    });
  });

  imagesToLoad.forEach(function(image) {
    intersectionObserver.observe(image);
  });
  
})();

3. 网站最佳实践

➣ 使用 hexo-abbrlink 插件生成文章链接

hexo 框架生成的博客地址默认是 :year/:month/:day/:title 这种格式的,也就是 /年/月/日/标题。当博客标题为中文时,生成的url链接中也出现中文,中文路径对于搜索引擎优化不友好。复制后的链接会被编码,非常不利于阅读,也不简洁。

使用 hexo-abbrlink 可以解决这个问题,安装插件:npm install hexo-abbrlink --save,在 _config.yml 中添加配置:

permalink: :year/:month/:day/:abbrlink.html/
permalink_defaults:
abbrlink:
  alg: crc32  # 算法:crc16(default) and crc32
  rep: hex    # 进制:dec(default) and hex

之后生成的博客文章就会变成这种:https://post.zz173.com/posts/8ddf18fb.html/,即使更新了文章标题,文章的链接也不会改变。

➣ 使用 hexo-filter-nofollow 规避安全风险

hexo-filter-nofollow 插件会为所有 链接添加属性 rel="noopener external nofollow noreferrer"

网站内部有大量的外链会影响网站的权重,不利于SEO。

➣ 使用 hexo-deployer-git 和 github workflow 进行自动化部署

静态资源打包生成完成后,我需要将其提交到对应的 github pagesgitee pages 仓库中,当需要部署多个仓库时,手动操作效率非常低。因此这里采用 hexo-deployer-git 插件进行自动化部署,可以向下面一样声明需要部署的仓库信息,如果有多个仓库直接声明多个 deploy 字段即可:

# Deployment
deploy:
  type: git
  repository: https://github.com/nojsja/blogs
  branch: master
  ignore_hidden:
    public: false
  message: update

值得说明的是,非付费用户 gitee pages 仓库不支持提交后自动部署。因此我采用的方案是只声明一个 deploy 部署仓库指向 github pages 仓库,然后再通过 github 仓库自带的 github workflow 服务配合 gitee-pages-action 这个脚本实现的 gitee 自动部署。它的原理就是使用 github 自动化工作流将 github 仓库的代码同步到 gitee 仓库中去,然后通过读取我们配置的 gitee 账户信息自动执行登录 gitee 账户并调用网页的手动部署接口,实现整个自动化部署流程。

github-workflow

4. 网站SEO优化

➣ 使用 hexo-generator-sitemap 插件自动生成网站地图

站点地图是什么:

  • 站点地图描述了一个网站的结构。它可以是一个任意形式的文档,用作网页设计的设计工具,也可以是列出网站中所有页面的一个网页,通常采用分级形式。这有助于访问者以及搜索引擎的机器人找到网站中的页面。
  • 一些开发者认为网站索引是组织网页的一种更合适的方式,但是网站索引通常是A-Z索引,只提供访问特定内容的入口,而一个网站地图为整个站点提供了一般的自顶向下的视图。
  • 网站地图让所有页面可被找到来增强搜索引擎优化的效果。

安装:

$: npm install hexo-generator-sitemap --save

配置文件_config.yml中添加相关字段:

# sitemap
sitemap:
  path: sitemap.xml
# page url
url: https://nojsja.github.io/blogs 

之后运行 hexo generate 之后就可以自动生成网站地图 sitemap.xml 了,接下来需要到 Google Search Console 记录自己的站点并提交相应的站点文件。

➣ 向 Google Search Console 提交个人网站地图

  • 登录 Google Search Console
  • 添加自己的网站信息


    Search Console
  • 可以通过几种方法验证所有权


    Search Console
  • 提交插件生成的 sitemap.xml
    sitemap.xml

Google Search Console 还能看到自己网站的点击情况、关键词索引情况等,非常方便。

参考


  1. Lighthouse与Google的移动端最佳实践
  2. Google web.dev

结语


学习前端性能优化的方方面面,一方面是对我们核心基础知识的考察,另一方面也能为我们遇到的一些实际问题提供处理思路,是每个前端人进阶的的必经之路。

以上就是本篇文章的所有内容,后续有需要还会继续更新…

你可能感兴趣的:(hexo个人网站优化探索)