搭建一个自己的博客
大约 4 分钟
# 成品
# 为什么搭建自己的博客
喷子多,不管理
被删帖,之前发了个把 unity 嵌入 cocos 的帖子后被管理删了
为什么不选择博客园、csdn?广告多,界面不好看
# 选择什么搭建框架?
之前看过了各种框架,中意的有 docusaurus、vuepress,最终选择了 vuepress
我的需求
博客:存在分类、标签功能,docusaurus 不符合国人操作习惯,vuepress 存在各种主题,甚至完整的博客插件
文档:两个都没问题,但是 vuepress 更方便配置和加功能
优缺点
docusaurus
- 优点:调试快
- 缺点:前端 Rect 框架(我不了解),文档缺少翻译,开箱即用的主题几乎没有
vuepress
- 优点:入门简单(了解 ts 就能用),插件丰富,开箱即用的主题多
- 缺点:调试慢
搭建配置
代码配置参考:https://github.com/1226085293/1226085293.github.io
这是我的网站源码,你们也可以直接 fork
图床(存放图片):https://www.imagehub.cc/
搜索引擎收录
目前只用到了百度,如果需要其他搜索引擎搜索到自己的网站可以去找下
统计服务
为了方便查看浏览量,用户数,可以使用第三方统计服务
我这里使用了 google analytics,不过统计数据上传没问题,如果是请求数据还是需要梯子
自动构建
使用 github actions,可以直接从 github 同步至 gitee,你只需要上传你的文章,github actions 自动构建并同步至 gitee pages,简直不要太方便
# 迁移文章
由于我没有多平台发布的习惯,而 cocos 论坛的文章一段时间之后就不能编辑了,这更加坚定了搭建自己博客的需求
试过四五个包括 AI 从 html 标签还原为 markdown 格式都不太行,有各种各样的问题
最终自己花了几小时写了段代码从 html 标签转译为 markdown(存在一些小问题),如下,需要的自取
// 帖子链接 url
fetch("https://forum.cocos.org/t/topic/137919", {
method: "GET",
headers: {
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9",
},
})
.then((response) => response.text())
.then((data) => {
let start_s = `<div class='post' itemprop='articleBody'>`;
let end_s = `<meta itemprop=`;
let start_n = data.indexOf(start_s) + start_s.length;
let html_s = data.slice(
start_n,
data.lastIndexOf("</div>", data.indexOf(end_s, start_n))
);
html_s = html_s
// 去除无用标签
.replace(/\<span class="badge([^(<\/)]+)\<\/span\>/g, "")
// 转换超链接
.replace(/(\<a href="([^"]+)"\>)([^\<]+)\<\/a\>/g, function (...args) {
return `[${args[3]}](${args[2]})`;
})
// 换行
.replace(/<br>/g, "\n")
// <
.replace(/</g, "<")
// >
.replace(/>/g, ">");
let convert_string_f = (value_s_: string, connect_b_ = false) => {
if (!value_s_) {
return value_s_;
}
let result_ss: string[] = [];
while (true) {
let match_result_as = [
// 0 标题
value_s_.match(/<h\d>([^]+?)<\/h\d>/),
// 1 图片
value_s_.match(
/<div class="lightbox-wrapper">([^]+?)<img src="([^]+?)"([^]+?)width="([^]+?)" height="([^]+?)"([^>\n]*)/
),
// 2 引用
value_s_.match(/<blockquote>([^(blockquote)]+)<\/blockquote>/),
// 3 内容
value_s_.match(/<p>([^]*?)<\/p>/),
// 4 选项标题
value_s_.match(/<li>([^]+?)<ul>/),
// 5 选项
value_s_.match(/<li>([^]+?)<\/li>/),
// 6 代码块
value_s_.match(/<code([^]+?)>([^]+?)([\n]*)<\/code>/),
// 7 单代码块
value_s_.match(/<code>([^]+?)([\n]*)<\/code>/),
// 8 加粗
value_s_.match(/<strong>([^]+?)<\/strong>/),
// 9 下划线
value_s_.match(/<hr>/),
// 10 图片
value_s_.match(
/<img src="([^]+?)"([^]+?)width="([^]+?)" height="([^]+?)"([^>]*)/
),
];
/** 最接近的下标 */
let closest_index_n = -1;
// 查找最近数据
{
match_result_as.forEach((v, k_n) => {
if (!v) {
return;
}
if (
closest_index_n === -1 ||
v.index! < match_result_as[closest_index_n]!.index! ||
(v.index! === match_result_as[closest_index_n]!.index! &&
v[0].length < match_result_as[closest_index_n]![0]!.length)
) {
closest_index_n = k_n;
}
});
}
if (closest_index_n === -1) {
break;
}
let match_result = match_result_as[closest_index_n]!;
// 链接头
if (!connect_b_) {
result_ss.push(value_s_.slice(0, match_result.index!));
}
// 更新内容
value_s_ = value_s_.slice(match_result.index! + match_result[0].length);
// 转换数据
switch (closest_index_n) {
// 标题
case 0: {
result_ss.push(
`${new Array(Number(match_result[0].match(/\d/)![0]))
.fill("#")
.join("")} ${match_result[1]}`
);
break;
}
// 图片
case 1: {
result_ss.push(
`![](${match_result[2]} =${match_result[4]}x${match_result[5]})`
);
break;
}
// 图片
case 10: {
result_ss.push(
`![](${match_result[1]} =${match_result[3]}x${match_result[4]})`
);
break;
}
// 引用
case 2: {
result_ss.push(
match_result[1]
.replace(/\<\/p\>\<p\>/g, "\n")
.replace(/(\<p\>)|(\<\/p\>)/g, "")
.replace(/\n/g, "\n> ")
.slice(1, -3)
);
break;
}
// 内容
case 3: {
result_ss.push(convert_string_f(match_result[1]));
break;
}
// 标题
case 4: {
result_ss.push(`- ${convert_string_f(match_result[1])}`);
break;
}
// 选项标题
case 5: {
result_ss.push(` - ${convert_string_f(match_result[1])}`);
break;
}
// 代码块
case 6: {
let code_s = match_result[2].replace(
/<span class="hljs-([^]+?)">([^]+?)<\/span>/g,
function (...args) {
return args[2];
}
);
let language_s =
match_result[1].match(/class="lang-([^( |")]+)/)?.[1] ?? "";
result_ss.push(`\`\`\`${language_s}\n${code_s}\n\`\`\``);
break;
}
// 单代码块
case 7: {
let code_s = match_result[1].replace(
/<span class="hljs-([^]+?)">([^]+?)<\/span>/g,
function (...args) {
return args[2];
}
);
result_ss.push(`\`${code_s}\``);
break;
}
// 加粗
case 8: {
result_ss.push(`*${convert_string_f(match_result[1])}*`);
break;
}
// 下划线
case 9: {
result_ss.push(`\n---\n`);
break;
}
}
}
return result_ss.length === 0
? value_s_
: result_ss.join(connect_b_ ? "\n" : "");
};
html_s = convert_string_f(html_s, true);
console.log(html_s);
});