网站切换到 Hexo

一、Hexo 安装

Hexo 安装根据官方文档直接操作即可,安装前提是需要先安装 Nodejs(这里不再阐述直接略过)

npm install -g hexo-cli

Hexo 命令行工具安装完成后可以直接初始化一个样例项目,init 过程会 clone https://github.com/hexojs/hexo-starter.git 到本地,同时自动安装好相关依赖

# mritd.com 为目录名,个人习惯直接使用网站域名作为目录名称
hexo init mritd.com

进入目录启动样例站点

# 进入目录
cd mritd.com
# 启动本地服务器进行预览
hexo serve

hexo_demo

二、主题设置

基本的样例博客启动完成后就需要选择一个主题,主题实质上才决定博客功能,这里目前使用了 Fluid 主题,这个主题目前兼具了个人博客所需的所有功能,而且作者提交比较活跃,文档也比较全面。

# 下载主题
git clone https://github.com/fluid-dev/hexo-theme-fluid.git themes/fluid
# 切换到最新版本
(cd themes/fluid && git checkout -b v1.8.3 v1.8.3)

接下来修改 _config.yml 配置切换主题即可

# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: fluid

然后重新启动博客进行预览: hexo cl && hexo s

fluid_demo

关于主题其他配置可自行阅读 官方文档,文档有时可能更新不及时,可同时参考仓库内的 _config.yml 配置。

三、文章导入

关于 jekyll 博客的文章如何导入到 Hexo 中网上有很多脚本;但是实际上两个静态博客框架都是支持标准的 Markdown 语法书写的文章进行渲染,唯一区别就是每篇文章上的 “头”。

---
catalog: true
categories:
  - [Kubernetes]
  - [Golang]
date: 2018-11-25 11:11:28
excerpt: 最近在看 kubeadm 的源码,不过有些东西光看代码还是没法太清楚,还是需要实际运行才能看到具体代码怎么跑的,还得打断点 debug;无奈的是本机是 mac,debug 得在 Linux 下,so 研究了一下 remote debug
keywords: kubeadm,debug
multilingual: false
tags:
  - Golang
  - Kubernetes
title: 远程 Debug kubeadm
index_img: img/remote_debug.jpg
---

具体文章内容......

所以直接复制 jekyll 的 md 文件到 source/_posts 目录,并修改文档头部即可。

四、自动更新

目前博客部署在自己的 VPS 上,以前都是将博客生成的静态直接使用 nginx 发布出去的;但是面临的问题就是每次博客更新都要手动去 VPS 更新,虽然可以写一些 CI 脚本但是并不算智能;得益于 Golang 官方完善的标准库支持,这次直接几行代码写一个静态服务器,同时拦截特定 URL 来更新博客:

package main

import (
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path"
)

func main() {
	http.Handle("/", fileServerWithCustom404(http.Dir("/data")))
	http.HandleFunc("/update", update)

	fmt.Println("Updating WebSite...")
	_, err := gitPull()
	if err != nil {
		fmt.Printf("WebSite update failed: %s", err)
	}

	fmt.Println("HTTP Server Listen at [:8080]...")
	_ = http.ListenAndServe(":8080", nil)
}

// POST 请求 /update 触发 git pull 更新博客
func update(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		w.WriteHeader(http.StatusBadRequest)
		_, _ = w.Write([]byte("only support POST method.\n"))
		return
	}
	bs, err := gitPull()
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		_, _ = w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(bs)
}

// 包装一下 404 状态码,返回自定义的 404 页面
func fileServerWithCustom404(fs http.FileSystem) http.Handler {
	fsh := http.FileServer(fs)
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, err := fs.Open(path.Clean(r.URL.Path))
		if os.IsNotExist(err) {
			r.URL.Path = "/404.html"
		}
		fsh.ServeHTTP(w, r)
	})
}

func gitPull() (msg []byte, err error) {
	cmd := exec.Command("git", "pull")
	cmd.Dir = "/data"
	return cmd.CombinedOutput()
}

五、Docker 化

有了上面的静态服务器,写个 Dockerfile 将 Hexo 生成的静态文件打包即可:

FROM golang:1.15-alpine3.12 AS builder

ENV GO111MODULE on

COPY goserver /go/src/github.com/mritd/hexo/goserver

WORKDIR /go/src/github.com/mritd/hexo/goserver

RUN set -e \
    && go install

FROM alpine:3.12 AS dist

LABEL maintainer="mritd <mritd@linux.com>"

ENV TZ Asia/Shanghai
ENV REPO https://github.com/mritd/mritd.com.git

COPY --from=builder /go/bin/goserver /usr/local/bin/goserver

RUN set -e \
    && apk upgrade \
    && apk add bash tzdata git \
    && git clone ${REPO} /data \
    && ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime \
    && echo ${TZ} > /etc/timezone \
    && rm -rf /var/cache/apk/*

WORKDIR /data

CMD ["goserver"]

镜像运行后将使用 /data 目录最为静态文件目录进行发布,Hexo 生成的静态文件(public 目录)也会完整的 clone 到当前目录,此后使用 POST 请求访问 /update 即可触发从 Github 更新博客内容。

六、Travis CI 集成

所有就绪以后在主仓库增加 .travis.yml 配置来联动 travis ci;由于每次 push 到 Github 的内容实际上已经是本地生成的 public 目录,所以 CI 只需要通知服务器更新即可;强迫症又加了一个 Telegram 通知,每次触发更新完成后 Telegram 再给自己推送一下:

language: go

git:
  quiet: true

script:
- curl -X POST ${CALLBACK}

after_script:
- curl -X POST https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage -d chat_id=${TELEGRAM_CHAT_ID} -d "text=mritd.com deployed."

七、gulp 优化

由于目前一些配图啥的还是存储在服务器本地,所以图片等比较大的静态文件仍然是访问瓶颈,这时候可以借助 gulp 来压缩并进行优化:

# 安装 gulp
npm install -g gulp
# 安装 gulp 插件
npm install gulp-htmlclean gulp-htmlmin gulp-minify-css gulp-uglify-es gulp-imagemin --save
# 重新 link 一下
npm link gulp

接下来编写 gulpfile.js 指定相关的优化任务

var gulp = require('gulp');
var minifycss = require('gulp-minify-css');
var uglify = require('gulp-uglify-es').default;
var htmlmin = require('gulp-htmlmin');
var htmlclean = require('gulp-htmlclean');
var imagemin = require('gulp-imagemin');

// 压缩html
gulp.task('minify-html', function() {
    return gulp.src('./public/**/*.html')
        .pipe(htmlclean())
        .pipe(htmlmin({
            removeComments: true,
            minifyJS: true,
            minifyCSS: true,
            minifyURLs: true,
        }))
        .pipe(gulp.dest('./public'))
});

// 压缩css
gulp.task('minify-css', function() {
    return gulp.src('./public/css/*.css')
        .pipe(minifycss({
            compatibility: '*'
        }))
        .pipe(gulp.dest('./public/css'));
});

// 压缩js
gulp.task('minify-js', function() {
    return gulp.src('./public/js/*.js', '!./public/js/*.min.js')
        .pipe(uglify())
        .pipe(gulp.dest('./public/js'));
});

// 压缩图片
gulp.task('minify-images', function() {
    return gulp.src('./public/img/*.*')
        .pipe(imagemin(
        [imagemin.gifsicle({'optimizationLevel': 3}),
        imagemin.mozjpeg({'progressive': true}),
        imagemin.optipng({'optimizationLevel': 7}),
        imagemin.svgo()],
        {'verbose': true}))
        .pipe(gulp.dest('./public/img'))
});

// 默认任务
// 这里默认没有运行 minify-js,因为我发现 js 压缩以后 PageSpeed 评分
// 莫明其妙的降低了,目前只优先考虑桌面浏览器的性能,暂不考虑移动端
gulp.task('default', gulp.parallel(
    'minify-html','minify-css','minify-images'
));

最后在每次部署时执行一下 gulp 命令即可完成优化: hexo cl && hexo g && gulp


本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 国际许可协议进行许可,转载请注明出处。