hexo博客搭建

HTTPS & HTTP/2

现在是 2019 年了,网站不是 HTTPS 和 HTTP/2 的感觉脱离时代了。HTTPS 已经不是因为安全方面的问题来考虑的了,而是后面所讲到的 PWA 里面很多最新的 HTML5 API 都是要求在 HTTPS 环境下才能正常工作的,所以要想让我们的博客更加的完美,必须要提供 HTTPS 环境。

可是,我并没有主机啊,没有服务器,怎么配证书?有主机的土豪的 HTTPS 证书可以通过 Let’s Encrypt 获取免费的,这个地方不深入讲了,可以参考 HTTPS 环境部署

我们今天介绍另一个免费的东西,不用服务器配置证书,通过 DNS 代理的形式,直接可以做到 HTTPS & HTTP/2 接入,这个东西叫 cloudflare

简单的介绍一下步骤:

  • 上 cloudflare 注册一个账号
  • 添加你的域名
  • 选择 Free Plan
  • 根据提示进行一系列的配置(就是些选项)
  • 最后会生成两个 DNS 的服务器地址
  • 进入你的域名运营商的配置后台,将默认的 DNS 服务配置成 cloudflare 生成的两个 DNS 服务地址

由于 DNS 服务全球更新速度较慢,可能得等个一天两天的服务才能稳定访问。总之,这时候,你的站点已经是 HTTPS & HTTP/2 的站点了。

cloudflare 的配置有很多,可以在后台进行配置,SSL 需要选择 FULL, 并且设置 HTTP REWRITE 让站点能自动从 HTTP 重定向到 HTTPS。还有很多有用的配置,大家可以自己把玩。

构建 AMP

AMP 全称为: Accelerated Mobile Pages,其目标是通过加速移动网络的网页加载从而提升体验, Google 推出的一种网页加速的标准,通过这种标准,够在是你的网站在 Google 的搜索结果页秒开。

那么如何让我们的博客能支持 AMP 呢?在 Hexo 中,已经有现成的插件(plugin)可以帮助我们完成这项工作,这个插件就是: hexo-generator-amp。

引入 hexo-generator-amp 插件

进入你的 Hexo 项目目录,执行:

1
npm install --save hexo-generator-amp

此时,博客已经具备生成 AMP 页面的基础了,由于 AMP 是一套独立的页面,hexo-generator-amp 插件只会对文章页面生成 AMP 页面,要想验证,只需要在原本文章的 URL 的基础上在后面加上 /amp 即可。

配置 _config.yml

hexo-generator-amp 插件是需要从 _config.yml 中读取配置才行,配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
\# amp config  
generator_amp:
templateDir: amp-template
assetDistDir: amp-dist
logo:
path: sample/sample-logo.png
width: 600
height: 60
substituteTitleImage:
path: sample/sample-substituteTitleImage.png
width: 1024
height: 800
warningLog: false \# To display warning, please set true.

其中,amp-template 是指明渲染 AMP 页面时候所使用的渲染模版,这种配置表明 AMP 是有一套自己的 theme, 如果想改变默认的 AMP 主题或者其他配置,可以对 amp-template 里面的内容进行二次开发。

修改主题模板文件

不同的主题需要修改的文件不同,next 主题需要修改 /themes/next/layout/_partials/head/custom-head.swig 文件,简单加入以下内容即可:

1
2
3
4
{% if is_post() && config.generator_amp %}
<link rel="amphtml" href="./amp/index.html">
{% endif %}
如果 Next 主题的版本比较老,找不到 /themes/next/layout/_partials/head/custom-head.swig 文件,就修改 /themes/next/layout/_partials/head/head.swig 文件,也是简单的把上面的代码加入到文件末尾即可。

hexo SEO

这个功能我单独总结了一一篇文章 hexo博客如何做seo?

添加 PWA 特性

什么是PWA?PWA 是一种渐进式的 Web App, 我们的博客其实就是一个 Web App, 渐进式的,就是慢慢来,一步一步的用一些 HTML5 的最新 API 的实现将我们的站点的用户体验做到极致。具体有关PWA可以看下《PWA 应用实战》或者点击这里

为什么要 PWA

博客站点是最适合改造成 PWA 的站点了,博客具有这么几个特点:

  • 内容更新不频繁,静态资源可能很久很久很久都不会更新(特别适合做离线缓存)
  • 博客是静态化页面(特别适合做整站的离线处理)
  • 博客一更新,最好能通知粉丝啦(这个理由真是一点都不违和)
  • 博客是个人的,想怎么搞怎么搞(可以尝试更多的 PWA 特性)
  • 。。。

怎么为博客加 PWA 特性

目前我们可以轻松做到为博客加入两点 PWA 特性

  • 添加到主屏:Manifest
  • 离线缓存:Service Worker

manifest.json

为了让博客能够添加到桌面,可以在 Hexo 的博客项目下的 /source 目录下增加 manifest.json 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{  
"name": "HexoBlog",
"short_name": "Peace",
"icons": \[
{
"src": "/img/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/img/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
\],
"start_url": "/",
"background_color": "#ffffff",
"display": "standalone",
"theme_color": "#2874f0"
}

这样,你的博客就可以在很多安卓机上被添加到桌面了(这个功能目前是需要在用户在系统设置里打开开关的)。iOS safari 目前对 Manifest 的标准支持的比较糟糕。

想 iOS Safari 也能体验更好的添加到桌面

由于 iOS 上没有对 manifest 标准支持的很好,并且只有 safari 浏览器有添加到主屏(快捷图标)的入口,那我们想 iOS 的添加到桌面的体验更好的话,需要改动 /themes/yourTheme 文件夹下的内容了,为了让每个博客页面在 iOS 的 Safari 浏览器下都能被添加到桌面,需要找到 themes/yourTheme/layout/_partial/head.ejs,然后在 <head> 的里面找个地方塞入如下 html 片段:

1
2
3
4
5
6
<!\-\- Add to home screen for Safari on iOS -->  
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Peace">
<link rel="apple-touch-icon" href="/img/icons/icon-152x152.png">
<link rel="shortcut icon" href="<%= config.root %>img/zoumiaojiang.ico">

当然,图片路径名称换成自己的就好了。

Service Worker

在 Webpack 构建环境下,有 sw-register-webpack-plugin 来帮助解决 Service Worker 的注册问题。那么在 Hexo 的开发环境中,我们也可以借助一个叫做 hexo-service-worker 插件来解决博客的 Service Worker 的注册问题。

hexo-pwa

既然我们使用了hexo,恰好就有他的插件hexo-pwa来帮我们实现

使用这个插件很简单,首先是安装插件:

1
npm install --save hexo-pwa

然后修改 _config.yml 让插件生效,通常我们的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# https://github.com/lavas-project/hexo-pwa
pwa:
manifest:
path: /manifest.json
body:
name: hexo
short_name: hexo
icons:
- src: /images/android-chrome-192x192.png
sizes: 192x192
type: image/png
- src: /images/android-chrome-512x512.png
sizes: 512x512
type: image/png
start_url: /index.html
theme_color: '#ffffff'
background_color: '#ffffff'
display: standalone
serviceWorker:
path: /sw.js
preload:
urls:
- /
posts: 5
opts:
networkTimeoutSeconds: 5
routes:
- pattern: !!js/regexp /hm.baidu.com/
strategy: networkOnly
- pattern: !!js/regexp /.*\.(js|css|jpg|jpeg|png|gif)$/
strategy: cacheFirst
- pattern: !!js/regexp /\//
strategy: networkFirst
priority: 5

再然后就是添加我们的icon图片,还要加一个sw.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* service worker 安装激活
*/

let dataCacheName = 'tiger-blog-data-v1'
let cacheName = 'tiger-blog-pwa-app-1'
let filesToCache = [
'/',
'/index.html',
'/article/index.html',
'/archive/index.html',
'/archives/index.html',
'/about/index.html',
'/categories/index.html',
'/js/bootstrap.scrollspy.js',
'/js/fancy-box.js',
'/js/helpers.js',
'/js/lazyload.js',
'/js/motion_fallback.js',
'/js/motion_global.js',
'/js/nav-toggle.js',
'/js/ua-parser.min.js',
'/vendors/jquery/index.js',
'/vendors/jquery/index.js',
'/vendors/velocity/bower.json',
'/vendors/velocity/velocity.js',
'/vendors/velocity/velocity.min.js',
'/vendors/velocity/velocity.ui.js',
'/vendors/velocity/velocity.ui.min.js',
'/vendors/fancybox/jquery.fancybox.js',
'/vendors/fancybox/jquery.fancybox.css',
'/vendors/fancybox/jquery.pack.js',
'/css/main.css',
'/fonts/icon-default/icomoon.eot',
'/fonts/selection.json',
'/style/fonts/icomoon.svg',
'/style/fonts/icomoon.ttf',
'/style/fonts/icomoon.woff',
'/img/avatar.png',
'/img/icons/icon_144x144.png',
'/img/icons/icon_192x192.png'
]

self.addEventListener('install', function (e) {
console.log('SW Install')
e.waitUntil(
caches.open(cacheName).then(function (cache) {
console.log('SW precaching')
return cache.addAll(filesToCache)
})
)
self.skipWaiting()
})

self.addEventListener('activate', function (e) {
console.log('SW Activate')
e.waitUntil(
caches.keys().then(function (keyList) {
return Promise.all(keyList.map(function (key) {
if (key !== cacheName && key !== dataCacheName) {
console.log('SW Removing old cache', key)
return caches.delete(key)
}
}))
})
)
return self.clients.claim()
})

self.addEventListener('fetch', function (e) {
console.log('SW Fetch', e.request.url)
// 如果数据相关的请求,需要请求更新缓存
let dataUrl = '/mockData/'
if (e.request.url.indexOf(dataUrl) > -1) {
e.respondWith(
caches.open(dataCacheName).then(function (cache) {
return fetch(e.request).then(function (response){
cache.put(e.request.url, response.clone())
return response
}).catch(function () {
return caches.match(e.request)
})
})
)
} else {
e.respondWith(
caches.match(e.request).then(function (response) {
return response || fetch(e.request)
})
)
}
})

注意:

其中 manifest.json文件是根据我们_config.yml文件中的body内容自动生成的,这里不用手动创建。

Service Worker 的生效必须依赖 HTTPS 的,想要对 Service Worker 有具体的了解可以 戳这

-->