ZBLOG(我这个博客系统)诞生的故事

ZBLOG(我这个博客系统)诞生的故事

0x01 起源

21 年的时候,我和一同学聊关于前后端分离的话题
结论就是后端某种意义上是浏览器和数据库之间的“中间件”
然后我就想:我的博客能不能也分离一下?就是博客文章、渲染框架、主题、插件彻底分离
于是在这个思想下,第一代 ZBLOG 诞生
渲染完全由浏览器负责,使用 git submodule 管理框架、主题等一堆东西
然而理想很丰满,现实很骨感,搜索引擎貌似完全不会执行 js 代码,于是我这玩意对于 seo 来说是致命的
(我有去搜过,搜索引擎完全没收录…)

0x02 SEO

SEO 问题必须解决,传统的方案是不要让浏览器渲染文章,然而我又不想把 Markdown"编译"成 HTML,直到我发现了一个问题
GitHub Actions界面,里面一堆GitHub pages的工作流
GitHub pages 是由 CI 处理的,咋的都要编译一遍,到头来省了个寂寞…

0x03 CI

不过 CI 的出现给了我另一个方案,反正咋的都要编译一遍,那让 CI 帮我打包成传统页面然后直接扔进 CDN 不就完了吗
顺带一提,这方面有比 GitHub 更专业的服务商,那就是 Cloudflare Pages

0x04 新 ZBLOG

新 ZBLOG 主要是兼容 Cloudflare Pages

这玩意是支持 nodejs 的,所以相关代码直接上 nodejs 就可以搞定

主要分成两部分,第一部分是 CI 下,包括新建博文等代码,另一部分则是 CI 上,生成 RSS、生成各种页面的代码

0x05 新建博文

这玩意好写,调 moment 生成文件名然后直接调 editor 打开就完了

const editor = require("editor");
const moment = require("moment");
const { join } = require("path");
editor(join("article", `${moment().format("YYYY-MM-DD_HH-MM-SS")}.html`));

0x06 最终编译

编译这一步…我同样卡在了变量作用域上
最终我采用的方法被我成为“分块”

readdir("article")
  .then((val) => {
    let tasks = [];
    val.forEach((file) => {
      tasks.push(
        readFile(join("article", file))
          // 预处理
          .then((article) => {
            // 省略具体实现细节
            // return new Promise();
          })
          // 加入RSS
          .then((feedItem) => {
            // 省略具体实现细节
            // return new Promise();
          })
        // 后面还有一堆,也都类似
      );
    });
    // 一起批量执行
    return Promise.all(tasks);
  })
  // 这中间还有一堆.then
  .then(() => console.log("ok"));

剩下的就是 MD 转 HTML、RSS 生成、HTML 生成…
这方面 MD 转 HTML 用的是showdown(来自“营销号”推荐),RSS 用的是rss库(这玩意自己找的)

PS: 网上各种营销号存在的最大意义就是让我们知道有这么个东西,然后…就没有然后了(不要指望你能从营销号那获得多少知识,真要了解还是要深入圈子)

至于 HTML 生成。。。我甚至写下过这么一段代码

function addHTMLFrame(title, body) {
  return `<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>${title}</title>
        <link rel="stylesheet" href="../style/style.css">
        <script type="module" src="../js/index.js"></script>
    </head>
    <body>
        ${body}
    </body>
    </html>`;
}

最终选择了模板引擎

0x07 模板引擎

这东西选择估计很多,必应node html template engine第一个就是 eta,那就他了

话说这玩意 logo 还真就是个 η

按照官网说的建立模板

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title><%= it.title %></title>
  </head>
  <body>
    <%~ it.description %>
  </body>
</html>

引用然后使用

const { Eta } = require("eta");
const eta = new Eta({ views: join("templates") });
// 此处省略一堆代码
              // MD转换HTML
              .then((item) => eta.renderAsync("article", item))
              .then((html) =>
                writeFile(
                  join("dist", "article", file.split(".")[0] + ".html"),
                  html
                )
              )

完活
主页的玩法也是一样,这里不再赘述
接下来就是写模板了,但是这玩意我不想写

0x08 “写”模板

说是写模板,其实是我抄我自己

老页面已经可以了,那能不能复用旧模板呢,答案是可以的,操作方法就是打开浏览器,打开主页和任意一篇文章,按下 Ctrl+S,然后我的到了这四个文件
HTML文件和文件夹
这些 HTML 就是渲染好的文件,改改就能用

0x09 烦人的时间问题

基本代码终于写完了…吗?
时间出问题了,变成了<span>Mon Nov 08 2021 23:38:46 GMT+0800 (China Standard Time)</span>
这个需要处理掉,方法也很简单,上 moment

              // 加入index.html
              .then(
                (feedItem) =>
                  new Promise((resolve, reject) => {
                    homepage.articles.push({
                      ...feedItem,
                      date:moment(feedItem.date).format("YYYY-MM-DD_HH-MM-SS")
                    });
                    resolve(feedItem);
                  })
              )

0x0A 巨大的主页和 RSS

由于生成代码的问题,这玩意产生的 RSS 和主页代码巨大,解决方案就是显示个预览,然后“打开页面阅读全文”

有没有觉得有点熟悉?熟悉就对了,不少页面都是这么干的(打开 APP 阅读全文)

代码改动则集中在 make.js 里

let cutedArticle = `${article
  .split("\n")
  .slice(1, config.showLineNum)
  .join("\n")}\n\n[查看全文](/article/${filename}.html)`;
let feedItem = {
  title: article.split("\n")[0].slice(2),
  description: showdownConverter.makeHtml(cutedArticle),
  article: showdownConverter.makeHtml(article),
  url: `/article/${filename}.html`,
  categories: [],
  author: config.webMaster,
};

改了一下 description,加了个 article

0x0B 上传到 git 并为对接 CF 做准备

CF Pages 支持 git 仓库,所以我们也要先准备 git 仓库

同时为了方便管理,所有外围组件都要分开

当然为了方便大家用,我还加了一些判断

0x0C CF Pages 部署

话说回来这还是我第一次用 cloudflare pages
当然我也希望它别出幺蛾子(当然最后这玩意用的很舒服)

CF Pages 操作还是挺简单的,一步一步来就好

进入CF仪表板,点击Workers 和 Pages,然后点击创建应用程序 切换到pages,点击连接到Git 点击连接到GitHub 点击install & Authorized 选择仓库并点击开始配置 配置构建命令、构建输出目录和环境变量并点击保存并部署

具体参数:
构建命令: npm run make
构建输出目录: dist
环境变量: NODE_ENV = production

点击继续处理项目 点击自定义域 点击设置自定义域 设置好域名并点击继续 点击激活域 点击完成DNS设置,然后点击检查DNS记录

剩下的就是静待 DNS 应用

0x0D 完工总结

终于解决了一堆 BUG 以后,我这个博客系统终于升级完成了

不过其实 UI 上看不出升级…,因为新旧版本差不了多少

这次倒是对 promise 有了新的理解,其他都属于比较常规的东西

这么搞也让我的博客彻底转移到了 CF 的网络里,总之这次折腾圆满完工

PS: CF Pages 还有很多好玩的东西,以后慢慢玩