Hexo的美化、优化以及Lighthouse极致追分
之前写过一篇 利用Hexo、GitHub Page、Typora写文章详细分享了我安装Hexo的过程,今天来聊一聊我这几天做文章迁移,选择Hexo主题,以及做主题修改和Hexo分页修改的过程,最后还会简单说一下如何在Lighthouse达到100分的跑分
Hexo美化
首先,Hexo安装完毕之后目前默认的是landscape这个主题,也很简洁,专注于写文章的人直接用完全没问题。不过我之前在使用Halo的时候用的就是Next主题,因此这次迁移第一个想法就是仍然使用next
主题安装
有意思的是我没有直接搜索next,而是在Hexo的官方主题库里面想要找到next,我想这是一种缘分,让我发现了Oranges这个主题,可以看一下Demo,这个主题比next还要简洁

去掉了所有可变按钮和分栏,这样就带来一个好处,移动端的时候选择其他标签按钮不需要再点一个下拉菜单了,就这一点点的简化让我选择了这个主题
安装过程很简单,只有两个步骤:
$ git clone https://github.com/zchengsite/hexo-theme-oranges.git themes/oranges修改hexo根目录的
_config.yml文件,把theme改成oranges即可
主题配置
在正式使用主题之前,还可以基于主题进行一些个性化配置,看得出来作者对于一些功能的开启有着很严格的标准,基本上在Readme文件当中罗列的功能都是基本需要的,可以在这里查看,由于作者的文档非常详细了,就不额外罗列了,我只简单说一下我开启的功能:
分类、标签、文章目录、RSS、评论、Google Analytics、上下页、全文搜索
图片懒加载没有开启,主要是觉得本来图片已经用了图床+CDN了,再多一个懒加载多此一举,而且观感不太好,要先看一个未加载的图片
主题修改
下面来聊一聊我改动了哪些地方,比较碎,咱们一点一点说
footer当中添加邮箱识别

在这里的所有图标都对应一个网址,因此作者在处理的时候就直接将配置文件的地址写入<a>标签的href里面了,但是作为邮箱,是需要在href里面加上一个mailto:的,可是由于里面有一个:的原因,直接写在配置文件里面会报错,因此我修改了代码如下:
1<div class="footer">
2 <div class="social">
3 <ul>
4 <% for(let item of theme.footer.social){ %>
5 <% if (item.name == "email") { %>
6 <li>
7 <a title="<%- item.name %>" href="mailto:<%- item.path %>">
8 <i class="iconfont icon-<%- item.icon %>"></i>
9 </a>
10 </li>
11 <% } else { %>
12 <li>
13 <a title="<%- item.name %>" href="<%- item.path %>">
14 <i class="iconfont icon-<%- item.icon %>"></i>
15 </a>
16 </li>
17 <% } %>
18 <% } %>
19 </ul>
20 </div>
21 <% for(let item of theme.footer.more){ %>
22 <div class="footer-more">
23 <% if (item.path) { %>
24 <a href="<%- item.path %>"><%- item.name %></a>
25 <% } else { %>
26 <%- item.name %>
27 <% } %>
28 </div>
29 <% } %>
30</div>
当配置文件里面的社交名为email的时候,在代码里面添加mailto:
首页文章列表去掉某个分类
这个需求我不知道其他人有没有,因为我的博客里面除了技术的文章,还会放一些小说,以及每日一段话类似之前的说说,全都堆在首页列表里面显得非常混乱,因此我修改了代码,将某个分类从列表中去掉(去掉几个都无所谓),代码改动不多,但是结构比较复杂,所以我把index.ejs全部贴出来,你们想要改的话直接复制就好,然后再手动改第11行即可
1<div class="container index">
2 <div class="post-list">
3 <!-- 遍历渲染文章 -->
4 <%
5 var prev = -10086;// prev year
6 var curr;// curr year, ever step be updated
7
8 page.posts.forEach(function(item) {
9 var mark = true;
10 item.categories.forEach(function(item1){
11 if(item1.name == "novel" || item1.name == "gossip"){
12 mark = false;
13 }
14 });
15 if(mark){
16 curr = item.date.year()
17 if (curr !== prev) {
18 prev = curr;
19
20 %>
21 <div class="content-title">
22 <h2>
23 <span><%- curr %></span>
24 </h2>
25 </div>
26 <%
27 }
28 %>
29 <div class="post-item" title="<%- item.title %>">
30 <div class="time-m-d"><%- item.date.format("MM-DD") %></div>
31 <div class="title">
32 <a href="<%- url_for(item.path) %>">
33 <% if(item.title !== "") { %>
34 <% if (item.top) { %>
35 <span><span title="<%= __('pinned') %>" class="icon iconfont icon-pin-top post-top"></span><%- item.title %></span>
36 <% } else { %>
37 <span><%- item.title %></span>
38 <% } %>
39 <% } else { %>
40 <span>untitled</span>
41 <% } %>
42 </a>
43 </div>
44 </div>
45 <% }}) %>
46 </div>
47 <nav class="post-navigation">
48 <% if(page.prev !== 0){ %>
49 <a href="<%- url_for(page.prev_link)%>"><i class="iconfont icon-angleleft"></i></a>
50 <% } %>
51 <span class="page-num"><%- page.current %> / <%- page.total -%></span>
52 <% if(page.next !== 0){ %>
53 <a href="<%- url_for(page.next_link)%>"><i class="iconfont icon-angleright"></i></a>
54 <% } %>
55 </nav>
56</div>
和主题原本不一样的是,我在列表当中将年度提取出来单独展示,这样观感好一些,当然也是从归档页抄来的

修改hexo-generator-index分页
需要注意的是,除非你不用分页(似乎不太可能),如果使用系统分页,那么系统自己再分页的时候,是不会把你想要去除的文章去掉的,这会导致一个问题,就是比如你按10个文章一分,但是主页只显示7个文章,那么分页后这个页面就是7个文章,如果正好某一页全都是你要去除的文章,那么这个页面上就会什么都没有,这和我们的初衷相违背,因此我们想要达到更好的观感,也需要修改Hexo的分页程序
修改的位置就在你博客的根目录node_modules文件夹里面,找到hexo-generator-index这个文件夹当中的generator.js这个文件,用vscode或者记事本打开也可以,在文章数组生成后,调用分页函数之前,添加一段代码,我的方法是新建一个数组,然后将老数组加一个判断,将未排除的文章推入新的数组即可,代码如下,改动从第16行开始
1'use strict';
2
3const pagination = require('hexo-pagination');
4const { sort } = require('timsort');
5
6module.exports = function(locals) {
7 const config = this.config;
8 const posts = locals.posts.sort(config.index_generator.order_by);
9 const temp_posts = [];
10
11 sort(posts.data, (a, b) => (b.sticky || 0) - (a.sticky || 0));
12
13 const paginationDir = config.pagination_dir || 'page';
14 const path = config.index_generator.path || '';
15
16 if(config.index_generator.exclude){
17 posts.forEach(element => {
18 var mark=true;
19 element.categories.forEach(function(categories){
20 config.index_generator.exclude_list.forEach(function(category){
21 if(categories.name == category){
22 mark=false;
23 }
24 });
25 });
26 if(mark){
27 temp_posts.push(element);
28 }
29 });
30 }
31
32 return pagination(path, config.index_generator.exclude ? temp_posts : posts, {
33 perPage: config.index_generator.per_page,
34 layout: ['index', 'archive'],
35 format: paginationDir + '/%d/',
36 data: {
37 __index: true
38 }
39 });
40};
然后在系统的配置文件_config.yml里面添加要排除的分类名称
1index_generator:
2 path: ''
3 per_page: 10
4 order_by: -date
5 exclude: true
6 exclude_list:
7 - novel
8 - gossip
到这里,基本上有关视觉的改动就差不多了
快!一定要快
接下来,我修改的部分主要是为了打开速度,既然选择了这么简洁的主题,那么Lighthouse跑分跑不到100分多丢人? 下面是我的主页的跑分,包括桌面端和移动端


要怎么做呢,其实google给出了很多建议,这里我只说一下我针对主题的一些做法
将所有静态文件保存在CDN
方法也很简单,将主题目录上传到github的一个公共仓库,然后发布一个release版本,这样你这个版本里面的静态文件都会缓存到jsdelivr里面,调用的方法也很简单
https://cdn.jsdelivr.net/gh/你的用户名/你的仓库名@Release版本号/source/iconfont/iconfont-min.css
将js文件异步加载
有了CDN地址之后,将主题里面所有的资源都改用CDN,主要是在/layout/_partial/header.ejs里面,还有几个零散的地方,自己看下source/*里面的文件,有哪些要修改的改下就可以了,Lighthouse跑一下也会有对应的提示,记得将所有的js文件的加载都添加async关键字,jquery.min 在这里是为了全文搜索使用的,加载的时候不涉及,jquery.fancybox.min-3.5.2 在这里是为了文章点击图片放大使用,也不涉及到一开始的页面渲染,所以放心加没关系,不要让这些js文件阻碍页面渲染
将所有js和css文件都进行压缩
这个是标准动作啦,直接搜索css压缩,会有很多在线压缩的网站,将文件复制进去点一下压缩,再创建一个XX-min.js的文件保存就可以了
至此经过一顿折腾,我的页面桌面模拟100分,移动端模拟99分,当然还有进步的空间,只是日后有机会再折腾吧
