Hexo - Generate Static Web Page

Heart

原来一直用CSDN博客记录一些学习心得,后来放弃了。主要原因为做排版太费时间,发表一篇文章,写作时间占比不多,其余时间都用来排版了。遂想用 Markdown 来写文章,寻寻觅觅许久,终于发现了 Hexo。

Hexo,静态博客,使用 Markdown 来写文章,一条命令即可直接发表文章。

  • 优点:让作者专注于文章内容而非网页排版,最后再由 Hexo 生成静态网页。
  • 缺点:需要自建博客,如准备域名、VPS……

由于 Hexo 生成的内容为静态网页,所以部分网友直接将它生成的网页部署在了 Github 上,这样 VPS 和域名都不用准备了。

静态网页的优点:

  • 页面内容相对稳定,不含特殊代码。
  • 容易被搜索引擎检索,更加适合 SEO 搜索引擎优化。
  • 不需通过数据库工作,所以访问速度比较快。

安装Hexo

首先需要搭建Node.js环境,详见Use Nvm to install Node.js

安装

1
2
3
4
5
:~$ npm install -g hexo-cli
:~$ hexo init blog
:~$ cd blog
:~/blog$ npm install
:~/blog$ hexo server

升级

1
2
3
:~$ cd blog
:~/blog$ npm outdated
:~/blog$ npm install

配置优化

这个有点麻烦,需要花时间调试。需要修改全局配置文件、皮肤配置文件,创建页面模板(标签、分类、归档、关于)等等。
但好在只需要配置一次即可。

创建网页模板

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
# create tags page
:~$ mkdir -p blog/sources/tags
:~$ echo '
---
title: tags
date: 2018-12-12 12:12
type: "tags"
sitemap:false
---
' > blog/source/tags/index.md

# Create Categore page
:~$ mkdir -p blog/sources/categories
:~$ echo '
---
title: categories
date: 2018-12-12 12:12
type: "categories"
sitemap:false
---
' >source/categories/index.md

# about page
:~$ mkdir -p blog/source/about
:~$ cat > /blog/source/about/index.md << EOF
---
title: about
date: 2018-12-23 17:47:10
type: "about"
sitemap: false
---

something to me!
nothing to now!
EOF

# 404 page
:~$ mkdir -p blog/source/404
:~$ cat >> blog/source/404/index.md << EOF
---
title: 404-Unkown Page
date: 2018-12-23 22:56
type: "commonweal"
layout: true
sitemap: false
---

<div>
<p style="text-align: center;font-family: cursive;font-size: 150px;font-weight: bold;line-height: 100px;letter-spacing: 5px;"><span>4</span><span>0</span><span>4</span></p>
<p style="text-align:center;font-family: cursive;font-size: 25px;font-weight: bold;line-height: 8px;letter-spacing: 5px">该页面不存在(´・ω・`)</p>
</div>
EOF

# Schedule
:~$ mkdir -p blog/source/schedule
:~$ cat >> blog/source/schedule << EOF
---
title: schedule
date: 2018-12-23 19:17:19
type: "schedule"
sitemap: false
---
EOF

第一篇blog - Hello Word

需要发表的源文件在blog/source/_posts/目录下。

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
# Method 1
:~$ cat > blog/source/_posts/helloword.md << EOF
---
title: Hello Word
date: 2018-12-17 23:03:29
tags: [program,hexo,default,none]
categories: [web,program]
sitemap: true
layout: false
---

Hello Word! This is My First Blog!

title -- 文章标题
date -- 文章的创建时间
tags -- 标签,可以指定一至多个
categories -- 分类,文章属于哪一类的。
sitemap -- 此文件是否包含在站点地图中
layout -- 是否进行网页渲染
EOF

# Method 2
:~$ echo '
---
title: TAGS
date: 2018-12-17 23:03:29
tags:
- program
- hexo
- default
- none
categories:
- web
- program
---
' > hexo.md

SiteMap

  • Bing Webmaster
  • Google Webmaster
  • Baidu Webmaster

Create Sitemap.xml

站点地图是一种文件,您可以通过该文件列出您网站上的网页,从而将您网站内容的组织架构告知Google和其他搜索引擎。搜索引擎网页抓取工具会读取此文件,以便更加智能地抓取您的网站。

1
2
3
4
5
6
7
:~$ npm install hexo-generator-sitemap --save
:~$ echo '
# hexo-generator-sitemap
sitemap:
path: sitemap.xml
template: ./sitemap_template.xml
' >> _config.yml

sitemap_template.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{% for post in posts %}
<url>
<loc>https://xxx.xxx.com{{ post.permalink | uriencode }}</loc>
{% if post.updated %}
<lastmod>{{ post.updated.toISOString() }}</lastmod>
{% elif post.date %}
<lastmod>{{ post.date.toISOString() }}</lastmod>
{% endif %}
</url>
{% endfor %}
</urlset>
' > sitemap_template.xml

source/sitemap.xsl

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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="2.0"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:html="http://www.w3.org/TR/REC-html40"
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="fileType">
<xsl:choose>
<xsl:when test="//sitemap:url">Sitemap</xsl:when>
<xsl:otherwise>SitemapIndex</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
<xsl:choose><xsl:when test="$fileType='Sitemap'">Sitemap</xsl:when>
<xsl:otherwise>Sitemap Index</xsl:otherwise>
</xsl:choose>
</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body {
margin: 0;
font-family: Helvetica, Arial, sans-serif;
font-size: 68.5%;
}
#content-head {
background-color: #4275f4;
padding: 20px 40px;
}
#content-head h1,
#content-head p,
#content-head a {
color: #fff;
font-size: 1.2em;
}
#content-head h1 {
font-size: 2em;
}
table {
margin: 20px 40px;
border: none;
border-collapse: collapse;
}
table {
font-size: 1em;
width: 75%;
}
th {
border-bottom: 1px solid #ccc;
text-align: left;
padding: 15px 5px;
font-size: 14px;
}
td {
padding: 10px 5px;
border-left: 3px solid #fff;
}
tr.stripe {
background-color: #f7f7f7;
}
table td a {
display: block;
}
table td a img {
max-height: 30px;
margin: 6px 3px;
}
</style>
</head>
<body>
<div id="content">
<div id="content-head">
<h1>XML Sitemap</h1>
<p>Generated by <a href="https://semperplugins.com/all-in-one-seo-pack-pro-version/?loc=aio_sitemap" target="_blank">All in One SEO Pack</a>, this is an XML Sitemap, meant to be consumed by search engines like Google or Bing.<br/>
You can find more information about XML sitemaps at <a href="http://sitemaps.org">sitemaps.org</a>.</p>
<p><xsl:choose>
<xsl:when test="$fileType='Sitemap'">
This sitemap contains <xsl:value-of select="count(sitemap:urlset/sitemap:url)"></xsl:value-of> URLs.</xsl:when>
<xsl:otherwise>This sitemap index contains <xsl:value-of select="count(sitemap:sitemapindex/sitemap:sitemap)"></xsl:value-of> sitemaps.</xsl:otherwise>
</xsl:choose></p>
</div>
<xsl:choose>
<xsl:when test="$fileType='Sitemap'">
<xsl:call-template name="sitemapTable"/></xsl:when>
<xsl:otherwise><xsl:call-template name="siteindexTable"/></xsl:otherwise>
</xsl:choose>
</div>
</body>
</html>
</xsl:template>
<xsl:template name="siteindexTable">
<table cellpadding="3">
<thead>
<tr>
<th width="50%">URL</th>
<th>Last Change</th>
</tr>
</thead>
<tbody>
<xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:for-each select="sitemap:sitemapindex/sitemap:sitemap">
<tr>
<xsl:if test="position() mod 2 != 1">
<xsl:attribute name="class">stripe</xsl:attribute>
</xsl:if>
<td>
<xsl:variable name="itemURL">
<xsl:value-of select="sitemap:loc"/>
</xsl:variable>
<a href="{$itemURL}">
<xsl:value-of select="sitemap:loc"/>
</a>
</td>
<td>
<xsl:value-of select="concat(substring(sitemap:lastmod,0,11),concat(' ', substring(sitemap:lastmod,12,5)))"/>
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
<xsl:template name="sitemapTable">
<xsl:variable name="sitemapType">
<xsl:for-each select="/*/namespace::*">
<xsl:if test="name()='video'">
<xsl:choose>
<xsl:when test="name()='video'">video</xsl:when>
</xsl:choose>
</xsl:if>
</xsl:for-each>
</xsl:variable>

<table cellpadding="3">
<thead>
<tr>
<th width="50%">URL</th>
<th>Images</th>
<th>Priority</th>
<th>Change Frequency</th>
<th>Last Change</th>
</tr>
</thead>
<tbody>
<xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:for-each select="sitemap:urlset/sitemap:url">
<tr>
<xsl:if test="position() mod 2 != 1">
<xsl:attribute name="class">stripe</xsl:attribute>
</xsl:if>
<td>
<xsl:variable name="itemURL">
<xsl:value-of select="sitemap:loc"/>
</xsl:variable>
<a href="{$itemURL}">
<xsl:value-of select="sitemap:loc"/>
</a>
</td>
<td>
<xsl:value-of select="count(image:image)"/>
</td>
<td>
<xsl:if test="string(number(sitemap:priority))!='NaN'">
<xsl:value-of select="concat(sitemap:priority*100,'%')"/>
</xsl:if>
</td>
<td>
<xsl:value-of select="concat(translate(substring(sitemap:changefreq, 1, 1),concat($lower, $upper),concat($upper, $lower)),substring(sitemap:changefreq, 2))"/>
</td>
<td>
<xsl:value-of select="concat(substring(sitemap:lastmod,0,11),concat(' ', substring(sitemap:lastmod,12,5)))"/>
</td>
<td>
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>

google/bing 收录我们的博客

  1. register Bing webmaster/Google Webmaster
  2. 进行网站所有权验证
  • DNS验证,即在DNS域名解析中添加TXT记录
  • <meta>验证,即在网站主页上添加指定的<meta>标签
  • 文件验证,将验证文件放在网站的根目录下
  1. 在sitemap下提交sitempa.xml

Baidu 收录我们的博客

因国内网站需要实名认证/备案,所以想使用百度站长工具需要注册[熊掌ID],而[熊掌ID]需要实名认证,即上传手持身份证的照片。

如果我们不需要Baidu Webmaster所提数据图表功能,则可在链接提交上直接提交我们的网址即可,不用进行站点认证。

验证网站

  • 为什么要验证网站
    站长平台推荐站长添加主站(您网站的链接也许会使用www 和非 www 两种网址,建议添加用户能够真实访问到的网址),添加并验证后,可证明您是该域名的拥有者,可以快捷批量添加子站点,查看所有子站数据,无需再一一验证您的子站点。
  • 如何验证网站
    首先如果您的网站已使用了百度统计,您可以使用统计账号登录平台,或者绑定站长平台与百度统计账号,站长平台支持您批量导入百度统计中的站点,您不需要再对网站进行验证。
    百度站长平台为未使用百度统计的站点提供三种验证方式:文件验证、html标签验证、CNAME验证。

验证完成后,将会认为您是网站的拥有者。为使您的网站一直保持验证通过的状态,请保留验证的文件、html标签或CNAME记录,会去定期检查验证记录。

如何选择链接提交方式

  1. 主动推送:最为快速的提交方式,推荐您将站点当天新产出链接立即通过此方式推送给百度,以保证新链接可以及时被百度收录。
  2. 自动推送:最为便捷的提交方式,请将自动推送的JS代码部署在站点的每一个页面源代码中,部署代码的页面在每次被浏览时,链接会被自动推送给百度。可以与主动推送配合使用。
  3. sitemap:您可以定期将网站链接放到sitemap中,然后将sitemap提交给百度。百度会周期性的抓取检查您提交的sitemap,对其中的链接进行处理,但收录速度慢于主动推送。
  4. 手动提交:一次性提交链接给百度,可以使用此种方式。

引用:viggoz

Hexo辅助函数#toc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{#################}
{### POST BODY ###}
{#################}
{% if toc(page.content).length > 1 %}
{% set next_toc_number = theme.toc.number %}
{% if page.toc_number !== undefined %}
{% set next_toc_number = page.toc_number %}
{% endif %}
{% set next_toc_max_depth = page.toc_max_depth|default(theme.toc.max_depth)|default(6) %}
{% set toc = toc(page.content,{list_number:false}) %}
{% if toc.length > 1 %}
<div class="post-toc-content">{{ toc }}</div>
{% endif %}
{% endif %}

hexo-leancloud-counter-security踩过的坑

当你按照 「leaferx教程」|「官方中文教程」 去集成 hexo-leancloud-counter-security 插件时,一定要注意要先让 Counter 初始化成功后,再集成 [hexo-leancloud-counter-security][toc_github_leancloud] 插件,否则文章阅读次数的地方会显示 [ 未初始化 | Counter not initialized! More info at console err msg.]

换句话说,先不开启 [hexo-leancloud-counter-security][toc_github_leancloud] 插件,当博客开始统计阅读次数后,再开启 [hexo-Leancloud-counter-security][toc_github_leancloud] 插件。

详细步骤即:

  1. 先按 leaferx教程 到「3. 部署云引擎以保证访客数量不被随意篡改」
  2. 修改theme/next/_config.yml
    1
    2
    3
    4
    5
    6
    7
    leancloud_visitors:
    enable: true
    app_id: <<your app id>>
    app_key: <<your app key>>
    # Dependencies: https://github.com/theme-next/hexo-leancloud-counter-security
    security: false
    betterPerformance: false
  3. 生成博客,并浏览网页,
    1
    :~$ hexo g
  4. 查看文章的阅读次数是否正常统计,如果未正常显示,再仔细看看教程。
  5. 如果 leancloud 已成功运行,再选做 「leaferx教程」 的第4步 「4. 进一步设置权限(可选,建议设置)」
  6. 生成博客
    1
    :~$ hexo g 
  7. 生成 leancloud 本地数据库 leancloud.memo,并与 leancloud网站 合并数据库。
    1
    :~$ hexo d
  8. 此时sourcepublic 目录下全部生成了 leancloud.memo 文件,

Prefence:
Hexo-Web
Hexo-Github
Alan’s Blog
leaferx’s Blog