Hexo 搭建静态博客

上次搭的博客写了两篇 Hexo 的配置后就凉了,所以这次刚刚搭好的时候就没想做个记录,怕和上次一样,把写博客的热情全花在了搭建博客上。

系统平台是 Ubuntu 17.04,其他平台的安装过程可能会有一些不同,不过后面的配置还是一样的。这里只有安装配置过程,具体使用,还请移步官方文档。 建议先看完再进行操作!!!

安装

hexo 是一个基于 node 的静态博客生成工具,所以先安装 node :

sudo apt install nodejs

这样安装似乎没有像 windows 下那样顺带把 npm 也给安装了,所以还需要安装一下 npm :

sudo apt install npm

再接着安装 Hexo:

sudo npm install hexo -g

很多朋友会遇到 Permission denied 的错误,所以我们需要使用 sudo 安装

# 在有读写权限的目录下执行,Blog 可以换成你喜欢的名字
mkdir Blog && cd Blog
# 初始化 Blog
hexo init

不出问题,写作环境就安装好了,再测试下:

# 生成静态资源
hexo g
# 在本地启动 node 静态资源服务器
hexo s

打开命令行里面输出的 http://27.0.0.1:4000,就能看到一篇 hello world

这里把安装命令整理一下:

sudo apt install nodejs npm
sudo npm install hexo -g
mkdir Blog && cd Blog
hexo init
# 下面的命令是为了安装某些正常安装但安装失败的依赖
npm install -f

目录结构

完成最基本的安装后, Blog 的目录结构大概是这样的

├── node_modules
├── scaffolds
│   ├── draft.md
│   ├── page.md
│   └── post.md
├── source
│   └── _posts
│       └── hello-world.md
├── themes
│   └── landscape
├── package.json
└── _config.yml

每个都简单说明一下:

  • node_modules

    差不多是一个本地运行环境,一般情况下是不需要动它的

  • sacffolds

    里面都是模板文件,可以打开看看,后面会进行一些修改

  • source

    这里放的是我们的源文件,文章和图片等

  • themes

    这里放的是一些主题,不同的文件夹就是不同的主题,目录名就是主题名

  • package.json

    Blog 工程的配置文件,一般情况下也不会动

  • _config.yml

    站点配置文件,定制化需要对它进行一些修改,我们下文也叫它 站点配置文件

站点基础配置

首先打开 站点配置文件,将 #Site 信息根据你的情况配置:

# Site
title: "Backyard"
subtitle: "敲敲代码,扯扯蛋"
description: "dashMrl's 个人小站————笔记+随笔"
author: dashMrl
language: zh-Hans
timezone:

然后修改 # Deployment 部分:

# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
  type: git
  branch: master
  repo:
    github: git@github.com:dashMrl/dashMrl.github.io.git

这里默认你知道怎么启用 GithubPages 服务,避免每次部署输入密码,我们使用 ssh密钥的方式部署

完成这些基本配置,就可以比较舒服的开始写博客了,如果你还需要更多定制化,接着往下看。

主题配置

到现在我们还是使用的默认主题 —— landscape,以我的审美来看,还是挺挫的。这里我们选择 Next 主题,这也是 GItHub 上 star 最多的一个主题。

如果觉得 Next 主题样式还行,也能满足你的大部分需求,就用它吧,其他的主题可能真的会有很多小问题,亲测

每个主题文件下都有一个 _config.yml 文件,这里我们就叫它 主题配置文件

首先去 Github 下载 Next 主题的 release 版本,解压到 thems 目录下,改名 next ,然后修改 站点配置文件

# Extensions
theme: next

再次执行 hexo g && hexo s 就可以看到生效的主题。

关于一些基本的配置,Next 的使用文档上都有,这里就只调我觉得重要的讲

阅读更多按钮

默认情况下首页会将整篇文章显示出来,非常丑陋并且影响阅读,所以有时候只想显示一小段描述。

主题配置文件 中找到 auto_excerpt

# Automatically Excerpt. Not recommend.
# Please use <!-- more --> in the post to control excerpt accurately.
auto_excerpt:
  enable: true
  length: 80

上面这种方式是截取 前 80 字符作为描述,如果想要精确控制的话,关闭 auto_excerpt使用 <--! more --> 来截断。我比较懒,就直接默认截取前80了。

back 2 top 按钮设置

主题配置文件 找到 sidebar 设置项,将相应子设置改成:

  # Scroll percent label in b2t button.
  scrollpercent: true
 
  # Enable sidebar on narrow view (only for Muse | Mist).
  onmobile: true

这样就能够在 backtotop 按钮上显示当前阅读的百分比了。

字数统计

主题配置文件 找到 Post wordcount display settings ,修改成下面样:

# Post wordcount display settings
# Dependencies: https://github.com/willin/hexo-wordcount
post_wordcount:
  item_text: true
  wordcount: true
  min2read: true
  totalcount: true
  separated_meta: true

配置完后我们还需要安装 hexo-wordcount 插件:

npm install hexo-wordcount --save-dev

这样就能显示每篇文章字数和大概阅读时长,同时在页面底部显示整个站点的字数,,感觉挺有用的。

本地搜索

主题配置文件 中找到 #Local Search ,修改成这样:

# Local search
# Dependencies: https://github.com/flashlab/hexo-generator-search
local_search:
  enable: true
  # if auto, trigger search by changing input
  # if manual, trigger search by pressing enter key or search button
  trigger: auto
  # show top n results per article, show all results by setting to -1
  top_n_per_article: 1

然后在 站点配置文件 里你开心的位置加上/修改:

# Local Search
search:
  path: search.xml
  field: post
  format: html
  limit: 10000

最后安装插件:

npm install hexo-generator-search --save-dev

还有更多的细节配置,就不一个个讲了,自己看 主题配置文件 ,里面都有介绍,按照自己的需求配置就行了。

高级定制

有时候还需要对博客进行一些优化配置,比如资源压缩等,需要我们添加一些插件甚至修改框架文件。更多资源路径相关优化可参考 2022-03-26-Hexo资源路径优化

文章链接优化

默认情况下,文章链接是 year/month/day/title 的形式,这样的链接层级对搜索引擎很不友好,当标题里包含中文的时候链接还会因为编码的问题变得丑陋异常。这里我们使用 hexo-abbrlink 插件对此进行优化。

站点配置文件 里找到 #URL 配置部分,然后修改成下面这样:

# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: https://xinsbackyard.tech
root: /
permalink: posts/:abbrlink.html
permalink_defaults:
abbrlink:
  alg: crc32
  rep: hex

这样每篇文章就会有一个类似 f4a6041.html 的链接了,而且还提升了逼格。

配置完了记得安装插件(虽然应该先安装再配置来着的)

RSS 订阅

提供 RSS 订阅功能,让关注我们博客的朋友及时收到新文章的“推送”,虽然我自己没有用过 RSS ,但是感觉还是很牛逼的样子,既然这么牛逼,肯定要加上。

站点配置文件 中你开心的位置上加上:

# RSS
feed:
  type: atom
  path: atom.xml
  limit: 20
  hub:
  content:
  content_limit: 140
  content_limit_delim: ' '

然后安装 hexo-generator-feed 插件。

添加站点运行时长

在网页底部显示 本站已运行 0 年 12 天 1 小时 33 分钟 4 秒 这样的字样,虽然并没有什么实质上的作用,但是以后看着自己的博客运行了这么久,发布了多少篇文章还是挺不错的。

这里以 Next 主题为例,其它的主题应该类似的

在 next 文件夹找到 layout/_partials/footer.swig 文件,然后找到这一段:

{% if theme.footer.custom_text %}
  ...
{% endif %}

在它前面加上 <div id="showDays">本站已运行 0 年 0 天 0 小时 0 分钟 0 秒</div> ,然后在它后面加上:

<script>
  var seconds = 1000;
  var minutes = seconds * 60;
  var hours = minutes * 60;
  var days = hours * 24;
  var years = days * 365;
  var birthDay = Date.UTC(2017,12,19,14,00,00); // 这里设置建站时间
  setInterval(function() {
    var today = new Date();
    var todayYear = today.getFullYear();
    var todayMonth = today.getMonth()+1;
    var todayDate = today.getDate();
    var todayHour = today.getHours();
    var todayMinute = today.getMinutes();
    var todaySecond = today.getSeconds();
    var now = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
    var diff = now - birthDay;
    var diffYears = Math.floor(diff/years);
    var diffDays = Math.floor((diff/days)-diffYears*365);
    var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
    var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
    var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
      document.getElementById('showDays').innerHTML="本站已运行 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
  }, 1000);
</script>

这时候就可以在网页底部显示运行时间了。不过问题也来了,当我们在手机浏览器中加载网页的时候,底部因为太高而挡住了帖子中阅读更多按钮,所以为了避免这种情况,我们把 Powered by Hexo 等推广字样去掉(在这里对 Hexo 和 Next 说声抱歉)。

站点配置文件 里找到 footer: 配置,然后修改:

footer:
#...
  powered: false
  theme:
#...
    enable: false

这样就算完成了。

如果学过 web 开发的话,可以把它们改得“面目全非”

修改 tag 图标

每篇文章底部都会显示几个 #tagname ,这个 # 号觉着不怎么好看,换成图标。

在 next 文件夹中找到 layout/_macro/post.swig ,找到 :

 
{% if post.tags and post.tags.length and not is_index %}
 <div class="post-tags">
     {% for tag in post.tags %}
            <a href="{{ url_for(tag.path) }}" rel="tag"> #{{ tag.name }}</a>
         {% endfor %}
    </div>
{% endif %}

{{ tag.name }} 前面的 # 改成 <i class="fa fa-tag"></i> 。这样就 OK 了。

静态资源压缩

Hexo 生成的静态资源中有很多的空行空格,然后我们的图片也有比较大的优化空间,为了减小它们的体积,提高加载速速,需要对其进行一定程度的压缩。

这里我们使用 Gulp 来压缩资源,首先安装必要的依赖:

npm install gulp gulp-clean-css gulp-html-clean gulp-htmlmin gulp-imagemin gulp-uglify --save-dev

然后在博客根目录下添加 gulpfile.js 文件,并写入如下内容:

var gulp = require('gulp');
var minifycss = require('gulp-clean-css');
var uglify = require('gulp-uglify');
var htmlmin = require('gulp-htmlmin');
var htmlclean = require('gulp-htmlclean');
var imagemin = require('gulp-imagemin');
 
// 压缩html
gulp.task('minify-html', ()=> {
    return gulp.src('public/**/*.html')
        .pipe(htmlclean())
        .pipe(htmlmin({
            removeComments: true,
            collapseWhitespace: true,//压缩HTML
            removeEmptyAttributes: true,//删除所有空格作属性值 <input id="" /> ==> <input />
            minifyJS: true,
            minifyCSS: true,
            minifyURLs: true,
        }))
        .pipe(gulp.dest('public'))
});
// 压缩css
gulp.task('minify-css', ()=> {
    return gulp.src(['public/css/**/*.css', '!public/css/**/*min.css'])
        .pipe(minifycss({ compatibility: 'ie8' }))
        .pipe(gulp.dest('public/css'));
});
// 压缩js
gulp.task('minify-js',  ()=> {
    return gulp.src(['public/js/**/*.js', '!public/js/**/*min.js'])
        .pipe(uglify())
        .pipe(gulp.dest('public/js'));
});
// 压缩图片
gulp.task('minify-images',  ()=> {
    return gulp.src('public/images/**/*.*')
        .pipe(imagemin(
            [imagemin.gifsicle({ 'optimizationLevel': 3 }),
            imagemin.jpegtran({ 'progressive': true }),
//   在我电脑上下面这一行会报错
//            imagemin.optipng({ 'optimizationLevel': 5 }),
            imagemin.svgo()],
            { 'verbose': true }))
        .pipe(gulp.dest('public/images'))
});
// 默认任务
gulp.task('default', [
    'minify-html', 'minify-css', 'minify-js', 'minify-images'
]);

然后在每次部署博客之前都执行:

gulp

如果站点的文本文件比重大的话,压缩效果还是很可观的。

SEO 优化

其实 SEO 也可以放在上一节中,但是 SEO 算是比较不同的配置,所以就拿出来单独讲。

生成 sitemap

我们需要把站点内容主动推给搜索引擎,推送载体就是 sitemap。打开 站点配置文件 ,在你开心的位置添加上:

# Site Map
sitemap:
  path: sitemap.xml
baidusitemap:
  path: baidusitemap.xml

然后安装 hexo-generator-sitemaphexo-generator-baidu-sitemap 两个插件。

认证网站所有权

这里需要分 Google 和 百度 分别认证,具体怎么认证,有很多优秀的博客有讲,这里就不赘述了

主动/自动推送

这里主要是针对百度的,因为 Github 把百度的爬虫给屏蔽了(虽然不知道为什么,但觉得百度好委屈hhh)。在百度站长认证完网站所有权之后就可以推送链接了,有被动爬取(被屏蔽)、自动推送和主动推送三种方式。

要开启自动推送非常简单,Next 帮我们把推送脚本内置了,只需要在 主题配置文件 里开启 baidu_push: true 就可以了。

至于主动推送,就是我们按照一定格式手工推送链接。emmm,手工?不存在的,这么无聊的事情肯定要自动化,然后就是考虑推送时机,更新博客的时候最合适,所以我们写一个博客的 部署脚本

#!/bin/bash
statusCheck(){
    if [ $? != 0 ]
    then
        echo -n $1' failed!!\n'
        exit $?
    else
        echo -n $1' completed!!\n'
    fi
}
echo 'start cleaning...'
node_modules/hexo/bin/hexo clean
statusCheck 'cleaning public resource'
 
echo 'start generating...'
node_modules/hexo/bin/hexo g
statusCheck 'generating public resource'
 
echo 'start compressing by gulp...'
node_modules/gulp/bin/gulp.js
statusCheck 'compressing public resource'
 
echo 'start deploying...'
node_modules/hexo/bin/hexo d
statusCheck 'deploying to repository'
 
echo 'start upload sitemap to baidu'
cat public/sitemap.xml | grep loc| grep -o 'https://xinsbackyard.tech/posts/.*\.html' > public/urls.txt
curl -H 'Content-Type:text/plain' --data-binary @public/urls.txt "http://data.zz.baidu.com/urls?site=https://xinsbackyard.tech&token=tZapjdbbZwBxt7WV"
#rm public/urls.txt
statusCheck 'push links to baidu'
 
echo 'completed...'

PWA 改造

PWA(渐进式 WebApp)在国内还一直不愠不火,但是 PWA 在提高用户体验方面确实有很大的作用,国外有很多案例(没亲自考证)。更重要的一点是,如果你使用原生系统,并且使用 Chrome 浏览 PWA 改造过的站点,Chrome 会根据用户的浏览情况来弹出 添加该站点到主屏幕 的请求窗口,当点击确认后, 应用抽屉 里就会出现一个你站点的 “App”,你没看错,是和我们从应用商店安装的应用待在一个地方,而且还能在系统设置里看到它。

manifest.json

就像一个 Android App 一样,我们需要提供一个清单文件来描述我们的站点,它大概长这样:

{
  "name": "Backyard",
  "short_name": "Backyard",
  "description": "dashMrl's 后花园——笔记+随笔",
  "dir": "auto",
// 这里设置成 standalone 很重要,不然不会显示为一个单独的应用
  "display": "standalone",
// 下面的两个颜色可以设置一样,会配合图标生成一个启动页
  "theme_color": "#272727",
  "background_color": "#272727",
  "start_url": "/?pwa=true",
  "scope": "/",
// 下面是 PWA 安装到手机上后显示的图标,最高需要提供到 512x512(我找遍了都没找到我头像这种分辨率的图,QAQ)
  "icons": [
    {
      "src": "images/icons/touch48.png",
      "sizes": "48x48",
      "type": "image/png"
    },
    {
      "src": "images/icons/touch72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "images/icons/touch96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "images/icons/touch144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "images/icons/touch168.png",
      "sizes": "168x168",
      "type": "image/png"
    },
    {
      "src": "images/icons/touch192.png",
      "sizes": "192x192",
      "type": "image/png"
    }
  ]
}

然后把这个文件丢到 source 文件夹下面,再修改 .../themes/next/layout/_partials/head.swig 文件使得每个页面都声明 manifest :

...
<link rel="manifest" href="/manifest.json">
...

还有一些辅助我们生成这个文件的网站,大家可以自行搜索,如果想要深入了解这个文件,可以前往 MDN 上学习。

Service Worker

这算是 PWA 精髓所在了,它的作用可以不恰当地理解为缓存。当我们第一次浏览某个网页的时候,浏览器会尝试注册这个 ServiceWorker,此时处于 installing 状态,注册成功后它就会运行在一个单独的进程,并处于 active 状态,然后当我们请求我们站内资源的时候,请求就会先经过 sw ,如果它恰好有缓存的话,直接返回,否则进行网络请求。当我们下一次访问这个站点的时候,如果 sw 的缓存没有过期,我们就可以接着使用缓存(和浏览器本身缓存很像)。

说了这么多,那到底怎么才能使用 sw 呢?也非常简单,首选打开 站点配置文件 ,在合适的位置加入 :

# offline config passed to sw-precache
service-worker:
  maximumFileSizeToCacheInBytes: 5242880
  staticFileGlobs:
  - public/**/*.{js,html,css,png,jpg,gif,webp,svg,eot,ttf,woff,woff2}
  stripPrefix: public
  verbose: true

然后安装 hexo-offline 插件就可以了,这时候执行 hexo g 可以看到类似 “ INFO Total precache size is about 5.17 MB for 153 resources ” 的字样,然后在 public 目录下会出现一个 service-worker.js 文件,这就表示它能缓存我们整个站点的文件。

启用 HTTPS

PWA 要求站内所有资源都通过 HTTPS 传输,如果使用的 GithubPages 的话,默认开启 HTTPS ,不需要我们操心。但是如果配置了自定义域名,GitHub 提供的 HTTPS 就无法开启了,如果你也和我一样想省时省钱的话,就是用 cloudflare 来提供 HTTPS 服务吧。具体怎么玩,大家自己亲自去实践吧hhh。

到现在应该是写得差不多了,写教程类的文章总是最累的(所以我偷工减料),即怕说得不够清楚,又怕说得太多不利于读者思考,更怕误导读者,所以还是向所有为人师者致敬。