重建 Hexo 博客日志

重建 Hexo 博客日志

几百年前刚建立这个博客时几乎什么都不懂,胡乱作一气。尽管包管理稀烂,Bug 层出不穷,部署时一堆报错…… 但索性能运行起来。

最近把整个仓库推到 Github 做持续集成,数据也不那么容易遗失。刚开始看没问题,结果主题调用的资源全部变成相对路径了,一片报错。

剪不断,理还乱…… 烂摊不好收,就重新建一个

安装 Hexo

什么?您若想了解安装流程,还请移步至 Hexo 官网

  • Node.js 用 nvm 管理。

版本:

Shell
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
❯ nvm -v
1.1.10

❯ node -v
v12.22.12

❯ hexo version
hexo: 6.3.0
hexo-cli: 4.3.1
os: win32 10.0.22631
node: 12.22.12
v8: 7.8.279.23-node.57
uv: 1.40.0
zlib: 1.2.11
brotli: 1.0.9
ares: 1.18.1
modules: 72
nghttp2: 1.41.0
napi: 8
llhttp: 2.1.4
http_parser: 2.9.4
openssl: 1.1.1n
cldr: 37.0
icu: 67.1
tz: 2021a4
unicode: 13.0

更换渲染引擎

默认孬。即换,以免兼容问题。

hexo-renderer-markdown-it

卸载:

Shell
1
2
❯ npm un hexo-renderer-marked --save
好嘛,卸载 hexo-renderer-marked 中……

安装:

Shell
1
2
❯ npm i hexo-renderer-markdown-it --save
好嘛,安装 hexo-renderer-markdown-it 中……

配置:

_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
+ # 以下是扩展设置
+
+ ## hexo-renderer-markdown-it https://github.com/hexojs/hexo-renderer-markdown-it
+ markdown:
+ preset: 'default'
+ render:
+ html: true # 启用页内 HTML
+ xhtmlOut: false # 是否完全兼容 XHTML
+ langPrefix: 'language-'
+ breaks: false # 换行变 <br>
+ linkify: false # 长得像链接的变 <a>
+ typographer: true # 能够替换常见的排版元素,如©、卷曲引号、破折号等
+ quotes: '“”‘’'
+ enable_rules:
+ disable_rules:
+ plugins:
+ - markdown-it-container
+ - markdown-it-footnote
+ - markdown-it-ins
+ anchors:
+ level: 2
+ collisionSuffix: ''
+ permalink: false
+ permalinkClass: 'header-anchor'
+ permalinkSide: 'left'
+ permalinkSymbol: '¶'
+ case: 0
+ separator: '-'
+ images:
+ lazyload: false
+ prepend_root: false
+ post_asset: false
+ inline: false # https://markdown-it.github.io/markdown-it/#MarkdownIt.renderInline

安装并启用 Icarus 主题

Shell
1
2
❯ npm install hexo-theme-icarus
好嘛,安装 hexo-theme-icarus 中……
_config.yml
1
2
3
4
5
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
- theme: landscape
+ theme: icarus

设置评论系统

本文撰写时 Icarus 主题不支持 giscus 评论系统。只好手动添加到源码。

先随便设置,让界面不报错:

_config.icarus.yml
1
2
3
4
5
6
7
8
9
# Comment plugin configurations
# https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Comment/
comment:
- type: disqus
- # Disqus shortname
- shortname: ''
+ type: utterances # 实际上我已经把 giscus 代码覆盖到 node_modules/hexo-theme-icarus/layout/common/comment.jsx
+ repo: Username/Username.github.io
+ issue_term: title

覆盖前备份:

Shell
1
❯ cp node_modules/hexo-theme-icarus/layout/common/comment.jsx node_modules/hexo-theme-icarus/layout/common/comment.jsx node_modules/hexo-theme-icarus/layout/common/comment.jsx node_modules/hexo-theme-icarus/layout/common/comment.jsx.bak

giscus 官网设置好的配置覆盖到 node_modules/hexo-theme-icarus/layout/common/comment.jsx

node_modules/hexo-theme-icarus/layout/common/comment.jsx
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
return <div class="card">
<div class="card-content">
<h3 class="title is-5">{__('article.comments')}</h3>
+ <script src="https://giscus.app/client.js"
+ data-repo="Username/Username.github.io"
+ data-repo-id="XXxXXXXxXXXx"
+ data-category="Announcements"
+ data-category-id="XXX_xxXXxXXXxxXXXX"
+ data-mapping="title"
+ data-strict="1"
+ data-reactions-enabled="1"
+ data-emit-metadata="0"
+ data-input-position="top"
+ data-theme="light_tritanopia"
+ data-lang="zh-CN"
+ crossorigin="anonymous"
+ async>
+ </script>
- {(() => {
- try {
- let Comment = view.require('comment/' + comment.type);
- Comment = Comment.Cacheable ? Comment.Cacheable : Comment;
- return <Comment config={config} page={page} helper={helper} comment={comment} />;
- } catch (e) {
- logger.w(`Icarus cannot load comment "${comment.type}"`);
- return null;
- }
- })()}
+ {/* {(() => {
+ try {
+ let Comment = view.require('comment/' + comment.type);
+ Comment = Comment.Cacheable ? Comment.Cacheable : Comment;
+ return <Comment config={config} page={page} helper={helper} comment={comment} />;
+ } catch (e) {
+ logger.w(`Icarus cannot load comment "${comment.type}"`);
+ return null;
+ }
+ })()} */}
</div>
</div>;

配置 RSS 订阅

hexo-generator-feed

安装:

Shell
1
2
3
4
❯ npm install hexo-generator-feed --save

+ hexo-generator-feed@3.0.0
added 1 package from 1 contributor in 2.848s

配置:

_config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
+ ## hexo-generator-feed
+ feed:
+ enable: true
+ # type: atom
+ # path: atom.xml
+ type:
+ - atom
+ - rss2
+ path:
+ - atom.xml
+ - rss2.xml
+ limit: 20
+ hub:
+ content:
+ content_limit: 140
+ content_limit_delim: ' '
+ order_by: -date
+ icon: /images/PJ568.svg
+ autodiscovery: true
+ template:

嗯。好。

配置自动翻译

不想为国际化而重写文章。因此,我集成 translate.js

规划

顶栏右侧生成 “翻译” 按钮。按下展开菜单以选择语言。

问题在于 translate.js 生成的是 <select> 元素。难以做到按下按钮打开 <select> 元素。

我可以将 <select> 元素设定成透明,用 z-index 使它覆盖在 “翻译” 按钮上层,这样点击按钮位置实际上点到的是 <select> 元素。(哈,我聪明)

调整样式

创建并写入:

source/css/translate.css
1
+ .translateSelectLanguage{z-index:10;width:100%;height:100%;opacity:0;cursor:pointer;position:absolute;left:0}

设置翻译

创建并写入:

source/js/translate_lib.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+ function initTranslate() {
+ try{
+ translate.service.use('client.edge');
+ translate.listener.start();
+ // translate.language.setLocal('chinese_simplified');
+ translate.setAutoDiscriminateLocalLanguage();
+ translate.language.setUrlParamControl();
+ translate.ignore.class.push('notTranslate');
+ translate.nomenclature.append('chinese_simplified','english',`
+ 刘甜=Liu Tian
+ `);
+ translate.execute();
+ }
+ catch(e){console.log('翻译系统出错:' + e);}
+ }
+
+ window.addEventListener('load', initTranslate);

插入代码

不翻译页标题

确保标题不被翻译(我设置的 giscus 依赖):

先备份:

Shell
1
❯ cp node_modules/hexo-theme-icarus/layout/common/head.jsx node_modules/hexo-theme-icarus/layout/common/navbar.jsx node_modules/hexo-theme-icarus/layout/common/comment.jsx node_modules/hexo-theme-icarus/layout/common/head.jsx.bak

插入代码:

node_modules/hexo-theme-icarus/layout/common/head.jsx
1
2
- <title>{getPageTitle(page, config.title, helper)}</title>
+ <title class="notTranslate">{getPageTitle(page, config.title, helper)}</title>

引入设置

引入 translate.js 代码前备份:

Shell
1
❯ cp node_modules/hexo-theme-icarus/layout/common/comment.jsx node_modules/hexo-theme-icarus/layout/common/navbar.jsx node_modules/hexo-theme-icarus/layout/common/comment.jsx node_modules/hexo-theme-icarus/layout/common/navbar.jsx.bak

引入 translate.js 代码:

node_modules/hexo-theme-icarus/layout/common/navbar.jsx
1
2
<div class="navbar-end">
+ <script src="//lib.baomitu.com/translate.js/3.2.1/translate.js"></script><link rel="stylesheet" href="/css/translate.css"/><script src="/js/translate_lib.js" defer=""></script><a class="navbar-item" id="translate" rel="noopener" title="翻译"><i class="fa fa-language"></i></a>

评论区国际化

translate.js 无法翻译 <iframe> 元素内的文字。

giscus 的所有元素在 <iframe> 元素内。

我应在 giscus 加载前获取访问者的语言,在 giscus 加载时替换 giscus 的 data-lang

source/js/trans_giscus.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
// 获取用户使用的语种。
const getCurrentLanguage = function () {
var lang = translate.language.getCurrent();
var giscus_lang = "zh-CN";
switch (lang) {
case "chinese_traditional":
giscus_lang = "zh-TW";
break;
case "english":
giscus_lang = "en";
break;
case "spanish":
giscus_lang = "es";
break;
case "japanese":
giscus_lang = "ja";
break;
case "korean":
giscus_lang = "ko";
break;
case "french":
giscus_lang = "fr";
break;
case "arabic":
giscus_lang = "ar";
break;
default:
giscus_lang = "zh-CN";
break;
}
return giscus_lang;
};


var SetupGiscus = function (giscus_lang) {
const script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://giscus.app/client.js";


script.setAttribute("data-repo", "PJ-568/PJ-568.github.io");
script.setAttribute("data-repo-id", "R_kgDOHqFAPw");
script.setAttribute("data-category", "Announcements");
script.setAttribute("data-category-id", "DIC_kwDOHqFAP84CYqBu");

script.setAttribute("data-mapping", "title");
script.setAttribute("data-strict", "1");
script.setAttribute("data-reactions-enabled", "1");
script.setAttribute("data-emit-metadata", "0");
script.setAttribute("data-input-position", "top");
script.setAttribute("data-theme", "light_tritanopia");
script.setAttribute("data-lang", giscus_lang);
script.setAttribute("data-loading", "lazy");

script.crossOrigin = "anonymous";
script.async = true;
if (document.getElementById("giscus-container") != null) {
document.getElementById("giscus-container").appendChild(script);
}
};

window.addEventListener('load', () => SetupGiscus(getCurrentLanguage()));
node_modules/hexo-theme-icarus/layout/common/comment.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
return <div class="card">
<div class="card-content">
<h3 class="title is-5">{__('article.comments')}</h3>
- <script src="https://giscus.app/client.js"
- data-repo="Username/Username.github.io"
- data-repo-id="XXxXXXXxXXXx"
- data-category="Announcements"
- data-category-id="XXX_xxXXxXXXxxXXXX"
- data-mapping="title"
- data-strict="1"
- data-reactions-enabled="1"
- data-emit-metadata="0"
- data-input-position="top"
- data-theme="light_tritanopia"
- data-lang="zh-CN"
- crossorigin="anonymous"
- async>
- </script>
+ <div id="giscus-container"></div>
node_modules/hexo-theme-icarus/layout/common/navbar.jsx
1
2
3
  <script src="//lib.baomitu.com/translate.js/3.2.1/translate.js"></script><link rel="stylesheet" href="/css/translate.css"/><script src="/js/translate_lib.js" defer=""></script><a class="navbar-item" id="translate" rel="noopener" title="翻译"><i class="fa fa-language"></i></a>
+ <script src="/js/trans_giscus.js"></script>
{Object.keys(links).length ? <Fragment>

怎么 hexo clean | hexo s 测试没效果?不管了,我直接推上线。说不定上线了就好了。

确实好了。

自定义页脚

_config.icarus.yml
1
2
3
footer:
# Copyright text
+ copyright: <a href="//icp.gov.moe/?keyword=20230568" target="_blank" rel="noopener">萌 ICP 备 20230568 号</a>&nbsp;&nbsp;未特殊声明文章默认遵循 CC BY 4.0 许可协议

压缩静态文件

Hexo-neat

安装:

Shell
1
2
3
4
❯ npm install hexo-neat --save

+ hexo-neat@1.0.9
added 17 packages from 14 contributors in 4.12s

配置:

_config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+ ## hexo-neat
+ neat_enable: true
+ neat_html:
+ enable: true
+ exclude:
+ - games/lib/**
+ neat_css:
+ enable: true
+ exclude:
+ - '*.min.css'
+ neat_js: # js 一模炸,别动
+ enable: false
+ mangle: true
+ output:
+ compress:
+ exclude:
+ - '*.min.js'

自动推送至搜索引擎

hexo-submit-urls-to-search-engine

具体请依据配置文档

安装

Shell
1
2
3
4
❯ npm install --save hexo-submit-urls-to-search-engine

+ hexo-submit-urls-to-search-engine@2.1.0
added 79 packages from 81 contributors in 9.513s

配置:

_config.yml
1
2
3
4
5
6
7
8
9
10
# Deployment
## Docs: https://hexo.io/docs/one-command-deployment
- deploy:
- type: ''
+ # deploy:
+ # type: ''
+ deploy:
+ - type: cjh_google_url_submitter
+ - type: cjh_bing_url_submitter
+ - type: cjh_baidu_url_submitter
_config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+ hexo_submit_urls_to_search_engine:
+ submit_condition: count #链接被提交的条件,可选值:count | period 现仅支持count
+ count: 10 # 提交最新的10个链接
+ period: 900 # 提交修改时间在 900 秒内的链接
+ google: 0 # 是否向Google提交,可选值:1 | 0(0:否;1:是)
+ bing: 1 # 是否向bing提交,可选值:1 | 0(0:否;1:是)
+ baidu: 1 # 是否向baidu提交,可选值:1 | 0(0:否;1:是)
+ txt_path: submit_urls.txt ## 文本文档名, 需要推送的链接会保存在此文本文档里
+ baidu_host: https://Username.github.io ## 在百度站长平台中注册的域名
+ baidu_token: 请按照文档说明获取 ## 请注意这是您的秘钥, 所以请不要把它直接发布在公众仓库里!
+ bing_host: https://Username.github.io ## 在bing站长平台中注册的域名
+ bing_token: 请按照文档说明获取 ## 请注意这是您的秘钥, 所以请不要把它直接发布在公众仓库里!
+ google_host: https://Username.github.io ## 在google站长平台中注册的域名
+ google_key_file: Project.json #存放google key的json文件,放于网站根目录(与hexo _config.yml文件位置相同),请不要把json文件内容直接发布在公众仓库里!
+ google_proxy: http://127.0.0.1:8080 # 向谷歌提交网址所使用的系统 http 代理,填 0 不使用
+ replace: 0 # 是否替换链接中的部分字符串,可选值:1 | 0(0:否;1:是)
+ find_what: http://Username.github.io/blog
+ replace_with: https://cjh0613.com

持续集成

.github/workflows/Release.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
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
name: 【部署】

on:
workflow_dispatch:
push:
paths:
- '**'
- '!LICENSE'
- '!.github\workflows\**'

jobs:
hexo-deployment:
runs-on: ubuntu-latest
env:
TZ: Asia/Shanghai

steps:
- name: Checkout source
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '14.17.0'

- name: Restore file modification time
run: |
git ls-files -z | while read -d '' path; do touch -d "$(git log -1 --format="@%ct" "$path")" "$path"; done

- name: Install dependencies & Generate static files
run: |
node -v
npm i -g hexo-cli
npm i
[ -d auth ] && [ "$(ls -A auth)" ] && cp -vrf auth/* source/ || echo "auth 为空或不存在"
hexo clean
hexo g
hexo d

- name: Generate the sitemap
id: sitemap
uses: cicirello/generate-sitemap@v1
with:
path-to-root: ./public
base-url-path: https://blog.pj568.sbs/

- name: 移动特定文件
run: |
cp -v ./README.md public/README.md

- uses: JamesIves/github-pages-deploy-action@v4
env:
GIT_NAME: PJ-568
GIT_EMAIL: ${{ secrets.GIT_EMAIL }}
REPO: github.com/PJ-568/Blog
with:
token: ${{ secrets.GH_TOKEN }}
branch: master
repository-name: PJ-568/Blog
folder: ./public # The folder the action should deploy.

持续集成应用文件更改

刚改的几个文件都在本地 node_modules/ 文件夹内。它不被上传。服务器安装依赖也会覆盖。

将有更改的文件放在 assets/ 文件夹,在安装依赖后且部署前将它们覆盖到指定位置。

Shell
1
2
3
4
5
6
7
8
9
❯ ls assets/
╭───┬────────────────────┬──────┬────────┬─────────────╮
│ # │ name │ type │ size │ modified │
├───┼────────────────────┼──────┼────────┼─────────────┤
│ 0 │ assets\comment.jsx │ file │ 1.8 KB │ 7 hours ago │
│ 1 │ assets\footer.jsx │ file │ 3.8 KB │ 4 hours ago │
│ 2 │ assets\head.jsx │ file │ 8.3 KB │ 3 hours ago │
│ 3 │ assets\navbar.jsx │ file │ 4.7 KB │ 6 hours ago │
╰───┴────────────────────┴──────┴────────┴─────────────╯
.github/workflows/Release.yml
1
2
3
4
5
6
7
8
9
run: |
node -v
npm i -g hexo-cli
npm i
+ cp -rf assets/* node_modules/hexo-theme-icarus/layout/common/
[ -d auth ] && [ "$(ls -A auth)" ] && cp -vrf auth/* source/ || echo "auth 为空或不存在"
hexo clean
hexo g
hexo d
作者

PJ568

发布于

2023-09-23

更新于

2023-11-28

许可协议

评论