我很希望能在这里吐心中之快、记心中之想。
曾有过多次记录的念头,一直没有实施,这次终于部署了这个网站。

一、内容

文档

1. 使用主题并修改主题文件

本博客使用stellar主题,并修改/增加了部分代码。那么如何用此主题并修改呢。

  1. 转为本地主题

在根目录创建文件夹themes,将主题依赖从node_modules/hexo-theme-stellar复制到themes,并修改文件名为stellar

hexoconfig.yml中的theme: stellar,不变。

  1. 修改方法例
    1. 网站底部信息可修改:footer.ejs
    1. 博客列表item所展示信息,可修改:post_list/post_card.ejs
    • 比如这个文件中,可以发现可通过post获得当前item的信息,可以用console来输出查看其结构,比如我想展示标签的信息,可以用post.tags获得
themes/stellar/layout/_partial/main

.
├── article
│ ├── article_footer.ejs
│ ├── read_next.ejs
│ └── related_posts.ejs
├── footer.ejs
├── navbar
│ ├── article_banner.ejs
│ ├── breadcrumb
│ │ ├── blog.ejs
│ │ ├── note.ejs
│ │ ├── page.ejs
│ │ └── wiki.ejs
│ ├── dateinfo.ejs
│ ├── ghinfo.ejs
│ ├── nav_tabs_blog.ejs
│ └── nav_tabs_wiki.ejs
├── notebook
│ ├── note_card.ejs
│ ├── note_tags.ejs
│ ├── notebook_card.ejs
│ └── paginator.ejs
└── post_list
├── paginator.ejs
├── post_card.ejs
├── topic_card.ejs
└── wiki_card.ejs

2. 图片

访问外链图片需添加:

1
<meta name="referrer" content="no-referrer"/>

3. 评论功能

使用giscus,仓库momomo623/LifeNotes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
comments:
service: giscus
# giscus
# https://giscus.app/zh-CN
giscus:
src: https://giscus.app/client.js
data-repo: momomo623/LifeNotes # [在此输入仓库]
data-repo-id: # [在此输入仓库 ID]
data-category: Announcements # [在此输入分类名]
data-category-id:
data-mapping: pathname
data-strict: 0
data-reactions-enabled: 1
data-emit-metadata: 0
data-input-position: top # top, bottom
data-theme: preferred_color_scheme
data-lang: zh-CN
data-loading: lazy
crossorigin: anonymous

4. html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
your front-matter
---

{% raw %}
<html>
<head>
...
</head>
<body>
....
</body>
</html>
{% endraw %}

5. 代码块

[title] [lang:language] [url] [link text] [additional options]
1
code snippet

以 option:value 的格式指定额外选项,例如:line_number:false first_line:5。

额外选项 描述 默认值
line_number 显示行号 true
line_threshold 只有代码块的行数超过该阈值,才显示行数 0
highlight 启用代码高亮 true
first_line 指定第一个行号 1
mark 突出显示特定的行,每个值用逗号分隔。使用破折号指定数字范围。例如:mark:1,4-7,10 将标记第1、4至7和10行 -
wrap 用 <table> 包裹代码块 true

示例
普通的代码块

1
alert('Hello World!');

指定语言

1
[rectangle setX: 10 y: 10 width: 20 height: 20];

在文章中插入代码。

描述
1
array.map(callback[, thisArg])

附加说明和网址

描述1.js
1
2
_.compact([0, 1, false, 2, '', 3]);
=> [1, 2, 3]

6. 评论

指定本页所用的评论数据库

image-20250218124709925

1
2
3
4
5
6
7
giscus:

data-repo: momomo623/LifeNotes

data-mapping: number

data-term: 6

二、个性配置

1. 文章卡新增字数统计

  1. 找到 \themes\stellar\layout\_partial\main\post_list\post_card.ejs 文件
  2. 找到 //meta 处,代码修改后如下:
1
2
3
4
5
6
7
8
9
themes\stellar\layout\_partial\main\post_list\post_card.ejs// meta
el += '<div class="meta cap">';
el += '<span class="cap" id="post-meta">';
el += icon('default: calendar')
// time
el += `<time datetime="${date_xml(post.date)}">${date(post.date, config.date_format)}</time>`
<!-- 新增字数统计 新增一行-->
el += '<span class="post-count">&nbsp;'+ wordcount(post.content) +' 字 </span>';
el += '</span>';

2. 博客列表新增标签显示

blog/node_modules/hexo-theme-stellar/layout/_partial/main/post_list/post_card.ejs

blog/node_modules/hexo-theme-stellar/layout/_partial/main/post_list/post_card.ejs
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
<%
const poster = post.poster;
var obj = {
image: post.cover
};
if (poster) {
obj.headline = poster.headline;
obj.topic = poster.topic;
obj.caption = poster.caption;
obj.color = poster.color;
}
function div_default() {
var el = '';
el += '<article class="md-text" >';

// 封面
if (obj.image || theme.article.auto_cover) {
var cover_url;
if (obj.image != undefined) {
if (obj.image.includes('/')) {
cover_url = obj.image;
} else {
cover_url = 'https://source.unsplash.com/1280x640/?' + obj.image;
}
} else {
// 自动以 tags 作为关键词搜索封面
if (post.tags) {
var params = '';
post.tags.reverse().forEach((tag, i) => {
if (i > 0) {
params += ',';
}
params += tag.name;
});
cover_url = 'https://source.unsplash.com/1280x640/?' + params;
} else {
cover_url = 'https://source.unsplash.com/random/1280x640';
}
}
if (cover_url) {
el += '<div class="post-cover">';
el += '<img src="' + cover_url + '"/>';
el += '</div>';
}
}

// 标题
el += '<h2 class="post-title">';
el += post.title ? post.title : date(post.date, config.date_format);
el += '</h2>';

// 摘要
el += '<div class="excerpt';
if (theme.plugins.heti?.enable) {
el += ' heti';
}
el += '">';
el += '<p>';
if (post.excerpt) {
el += strip_html(post.excerpt);
} else if (post.description) {
el += post.description;
} else if (post.content && theme.article.auto_excerpt > 0) {
el += truncate(strip_html(post.content), {length: theme.article.auto_excerpt});
}
el += '</p>';
el += '</div>';

// meta
el += '<div class="meta cap" >';
el += '<span class="cap" id="post-meta" style="font-size: 0.9rem;"> ';
el += icon('default:calendar')
// time
el += `<time datetime="${date_xml(post.date)}">${date(post.date, config.date_format)}</time>`
el += '<span class="post-count">&nbsp;'+ wordcount(post.content) +' 字 </span>';
el += '</span>';
// cat
if (post.categories && post.categories.length > 0) {
if (post.layout === 'post' && post.categories && post.categories.length > 0) {
var cats = [];
if (post.categories) {
post.categories.forEach((cat, i) => {
cats.push(cat.name);
});
}
if (cats.length > 0) {
let cat = cats.shift();
// 获取原始样式并添加字体大小
let style = category_color(cat);
// 删除最后一个字符
style = style.slice(0, -1);
style += ';font-size: 0.9rem"'; // 添加字体大小并加回引号
el += '<span class="cap breadcrumb" ' + style + '>';
el += icon('default:category')
el += `<span>${cat}</span>`
el += '</span>';
}
}
}
// 新增:标签显示
// tags
if (post.layout === 'post' && post.tags && post.tags.length > 0) {
post.tags.forEach((tag, i) => {
el += '<span style="font-size: 0.9rem;margin-right: 4px; border-radius: 7px;">';
el += '<span style="color: #1eb4ef; margin-right: 2px;">#</span>';
el += '<span style="color: #1eb4ef;">' + tag.name + '</span>';
el += '</span>';
});
}

if (post.sticky) {
el += `<span class="pin">${icon('default:pin')}</span>`
}
el += '</div>';
el += '</article>';
return el;
}
function div_photo() {
var el = '';
el += '<div class="cover">';
el += '<img src="' + obj.image + '"/>';
if (obj.headline || obj.topic || obj.caption) {
el += '<div class="cover-info"';
if (obj.color) {
el += 'style="color:' + obj.color + '"';
}
if (obj.topic) {
el += 'position="top">';
} else {
el += 'position="bottom">';
}
if (obj.topic) {
el += '<div class="cap">' + obj.topic + '</div>';
}
if (obj.headline) {
el += '<div class="title">' + obj.headline + '</div>';
}
if (obj.caption) {
el += '<div class="cap">' + obj.caption + '</div>';
}
el += '</div>';

}
el += '</div>';
return el;
}
function div() {
if (obj.image && obj.image.length > 0 && obj.headline != undefined) {
return div_photo();
}
return div_default();
}
%>
<%- div() %>

3. 文章底部添加字数统计

  1. 安装 hexo-wordcount 插件:npm i hexo-wordcount --save
  2. themes/stellar/layout/_partial/main/footer.ejs 文件中,找到//footer:
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
<%
const content = theme.footer.content?.replace('{author.name}', (config.author || 'Anonymity'))?.replace('{theme.name}', stellar_info('name'))?.replace('{theme.version}', stellar_info('version'))?.replace('{theme.tree}', stellar_info('tree'))
function layoutDiv() {
var el = ''
el += `<footer class="page-footer${scrollreveal(' ')} footnote">`
el += '<hr>'
// sitemap
if (theme.footer.sitemap && Object.keys(theme.footer.sitemap).length > 0) {
el += '<div class="sitemap">'
for (let group of Object.keys(theme.footer.sitemap)) {
let items = theme.footer.sitemap[group]
if (items == undefined || items.length == 0) {
continue
}
el += '<div class="sitemap-group">'
el += '<span class="fs15">' + group + '</span>'
items.forEach((item, i) => {
el += '<a href="' + url_for(md_link(item)) + '">'
el += __(md_text(item))
el += '</a>'
});
el += '</div>'
}
el += '</div>'
}
// footer
el += '<div class="text">'
if (content) {
el += markdown(content)
}
el += '<div style="font-size: 1rem;text-align: center; margin: 1rem 0; color:var(--text-p4);">'
el += '发表了 ' + site.posts.length + ' 篇文章 🔸 总计 ' + totalcount(site) + ' 字'
el += '</div>'
el += '</div></footer>'
return el
}
%>
<%- layoutDiv() %>

4. 编辑本页功能

在右侧添加编辑本页功能。

在config中添加配置,也可以不添加这个,直接写死到toc.ejs中

_config.stellar.yml
1
2
3
4
5
6
edit_page:
enable: true
repo: momomo623/blog
branch: main
base_path: source
edit_text: 编辑本页

修改主题代码。新增的代码:突出显示特定的行

themes/stellar/layout/_partial/widgets/toc.ejs
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
<%

function layoutTocBody() {
if (toc(page.content).length > 0) {
return toc(page.content, {
list_number: item.list_number,
min_depth: item.min_depth,
max_depth: item.max_depth
})
}
return ''
}

function layoutTocHeader(title) {
var el = ''
el += `<div class="widget-header dis-select">`
el += `<span class="name">${title || __("meta.toc")}</span>`
el += `<a class="cap-action" onclick="sidebar.toggleTOC()" >${icon('default:rightbar')}</a>`
el += `</div>`
return el
}

function layoutToc(fallback) {
const tocBody = layoutTocBody()
if (tocBody.length == 0) {
return ''
}
var el = ''
el += `<widget class="widget-wrapper${scrollreveal(' ')} toc" id="data-toc" collapse="${item.collapse}">`
el += layoutTocHeader()
el += `<div class="widget-body">`
el += tocBody
el += `</div>`
el += `</widget>`
return el
}

function layoutDiv(fallback) {
console.log(page)

const editBtn = partial('components/edit', {map: item.edit_this_page})
const tocBody = layoutTocBody()
if (tocBody.trim().length == 0 && editBtn.trim().length == 0) {
return ''
}
var el = ''
el += `<widget class="widget-wrapper${scrollreveal(' ')} toc" id="data-toc" collapse="${item.collapse}">`
if (tocBody.length > 0) {
el += layoutTocHeader()
el += `<div class="widget-body">`
el += tocBody
el += `</div>`
}
el += `<div class="widget-footer">`
el += editBtn
el += `<a class="top" onclick="util.scrollTop()">`
el += icon('default:upup')
el += `<span>${__('btn.top')}</span>`
el += `</a>`
if (theme.comments.service && theme.comments.service.length > 0) {
if (page.comments == undefined || page.comments != false) {
el += `<a class="buttom" onclick="util.scrollComment()">`
el += icon('default:tocomment')
el += `<span>${__('btn.comments')}</span>`
el += `</a>`
}
}
if (theme.edit_page?.enable && page.source) {
const repo = theme.edit_page.repo
const branch = theme.edit_page.branch || 'main'
const basePath = theme.edit_page.base_path || ''
const editUrl = `https://github.com/${repo}/edit/${branch}/${basePath}/${page.source}`

el += `<a href="${editUrl}" target="_blank">`
el += icon('default:edit')
el += `<span>${theme.edit_page.edit_text || __(编辑本页)}</span>`
el += `</a>`
}
el += `</div>`
el += `</widget>`


return el
}

%>

<%- layoutDiv() %>

5. 代码块滚动条

来自

在 themes\stellar\source\js\ 中新建 custom.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 给超长代码块增加滚动条
function adjustCodeBlockHeight() {
document.addEventListener("DOMContentLoaded", function () {
// 选择所有的.md-text元素
var codeBlocks = document.querySelectorAll('.md-text');
// 遍历每个.md-text元素
codeBlocks.forEach(function (block) {
// 检查是否包含.highlight类的子元素,且父元素高度超过500px
var highlightBlocks = block.querySelectorAll('.highlight');
highlightBlocks.forEach(function (highlightBlock) {
if (highlightBlock.clientHeight > 800) {
highlightBlock.style.maxHeight = '300px';
highlightBlock.style.overflow = 'auto';
}
});
});
});
}

adjustCodeBlockHeight()

在 _config.yml 文件中,最后一行加入以下指令:

1
2
3
4
5
inject:
script:
# 自定义js
- <script type="text/javascript" src="/js/custom.js?1"></script>
- <script src="/js/custom.js?1"></script>

需要注意的是,Stellar 主题有 tabs 分栏容器,如果在容器中写入长代码,这段 js 是不生效的。
因为这时候生成的 HTML 结构可能与原始代码块不同,导致 JavaScript 选择器无法正确找到目标元素。
解决方法也很简单,可以直接在 Markdown 文件中使用内联样式来设置代码块的最大高度和滚动条。

1
2
3
4
5
6
7
<div style="max-height: 300px; max-width: 100%; overflow: auto;">
```javascript
// 这里是你的代码
function example() {
console.log("Hello, world!");
}
</div>

三、部署

GitHub部署+绑定域名

1 双仓库策略

  1. blog为私有仓库,存放本博客项目
  2. LifeNotes为公开仓库,存放生产文件,即hexopublic文件夹

2 配置 GitHub Actions

1. 配置 GitHub Actions

其中user.name、user.email请替换为自己的。

创建文件:.github/workflows/deploy.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
name: ChongWen's Blog CI/CD # 脚本 workflow 名称

on:
push:
branches: [main, master] # 当监测 main,master 的 push
paths: # 监测所有 source 目录下的文件变动,所有 yml,json 后缀文件的变动。
- '*.json'
- '**.yml'
- '**/source/**'

jobs:
blog: # 任务名称
timeout-minutes: 30 # 设置 30 分钟超时
runs-on: ubuntu-latest # 指定最新 ubuntu 系统
steps:
- uses: actions/checkout@v4 # 拉取仓库代码
- uses: actions/setup-node@v4 # 设置 node.js 环境
- name: Cache node_modules # 缓存 node_modules,提高编译速度,毕竟每月只有 2000 分钟。
uses: actions/cache@v4 # 亲测 Github 服务器编译速度比我自己电脑都快,如果每次构建按5分钟计算,我们每个月可以免费部署 400 次,Github yyds!!!
env:
cache-name: cache-node-modules
with:
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Init Node.js # 安装源代码所需插件
run: |
npm install
echo "init node successful"
- name: Install Hexo-cli # 安装 Hexo
run: |
npm install -g hexo-cli --save
echo "install hexo successful"
- name: Build Blog # 编译创建静态博客文件
run: |
hexo clean
hexo generate
# 确保 CNAME 文件存在
echo "chongwenz.cn" > public/CNAME
echo "build blog successful"
- name: Deploy ChongWen's Blog # 设置 git 信息并推送静态博客文件
run: |
git config --global user.name "momomo623"
git config --global user.email "28417416@qq.com"
hexo deploy
- name: Verify Git Identity
run: |
echo "Current Git user.name: $(git config --global user.name)"
echo "Current Git user.email: $(git config --global user.email)"
- run: echo "Deploy Successful!"

2. 创建token、配置config

网址:https://github.com/settings/tokens/new。

选择权限:repo、workflow

_config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13

deploy:

\- type: git

​ repository:

​ github: https://你的token@github.com/momomo623/LifeNotes.git,main

​ name:

​ email:

3. 配置私有仓库

网址:https://github.com/用户名/仓库名/settings/actions

  • Actions permissions:Allow all actions and reusable workflows
  • Workflow permissions:Read and write permissions和Allow GitHub Actions to create and approve pull requests

4. 配置公共仓库

网址:https://github.com/用户名/仓库名/settings/pages

image-20250217155848783

配置到这里,可以测试action情况、Github静态页面情况。将代码提交到私有仓库,可在Github上查看action情况,如果错误也可以根据log去修改。通过后,可查看公告仓库,是否有新的提交。然后可访问:https://momomo623.github.io/LifeNotes

3. 域名绑定设置

  1. DNS配置

    1
    2
    # DNS记录
    CNAME @ → momomo623.github.io
  2. Hexo配置

    1
    2
    3
    # _config.yml
    url: https://chongwenz.cn
    root: /
1
2
# source/CNAME 新建文件
将我们的自定义域名填写进去。
  1. GitHub设置
    • 进入 LifeNotes 仓库 Settings → Pages
    • Custom domain 输入 chongwenz.cn
    • 勾选 “Enforce HTTPS”

4. 验证部署

1
2
3
4
5
6
# 本地测试
hexo clean && hexo g && hexo s

# 查看部署状态
https://github.com/momomo623/blog/actions
https://chongwenz.cn



总访问
发表了 19 篇文章 🔸 总计 43.8k 字