静态博客生成器

1月前

实现一个静态博客生成的工具,本质上还是实现一个后端博客系统,唯一不同从数据库变成了 markdown 文件,原本读取数据库的操作,变成了读取本地 markdown 文件,后者通过 markdown 渲染工具转换成 html 然后插入到定义好的主题模板中去,最后导出 html 数据。

Markdown 数据

遍历一个定义好的文件夹,找出其中所有的 .md 文件,将文件名称作为网页地址后面的一部分 (slug)。此时已经有了 slug 和文章内容了,还需要一些诸如:标题、日期、分类、标签之类的参数。比如 hexo 采用了下面的格式来实现,然后通过正则获取到这部分的数据,最后解析成 JSON 数据:

title: Hello World
date: 2019-11-11
tags: []
categories: category
---

这样就实现了原本通过 select * from posts order by created desc 来获取到的所有文章内容。

路由

获取到文章内容和在主题或者全局设定好的布局配置之后,需要注册路由,将对应的数据展示出来,这样才可以在写主题、文章时实时预览前端的效果。

以 express 为例,文章部分的路由可以如下定义:

const app = express()

posts.forEach(row => {
  app.get(`/${row.slug}`, (_, res) => {
    res.render('post.ejs', {
      title: row.title,
      content: row.content,
      date: row.date,
      categories: row.categories,
      tags: row.tags
    })
  })
})

模板

hexo 为例,hexo 采用了 ejs 这种模板,它可以实现循环、条件判断、引入其他模板等功能,这样我们可以主题将模板拆分到足够小的颗粒。

<%- include header.ejs %>
<h1><%= title %></h1>
<div><%= created %></div>
<div class="post">
  <%- content %>
</div>
<%- include footer.ejs %>

中间件

我们虽然可以在每个路由下,通过 res.render 注入所有需要所有文章、网站配置、主题配置等数据。既然是重复的行为,可以使用中间件来实现,将所有数据绑定到 res.locals 上,就可以提供给 ejs 渲染输出。

// middware.js
module.exports = () => {
    return (_, res, next) => {
        res.locals = {}
        next()
    }
}

使用中间件也很简单:

// router.js
app.get('/', middware, (req, res) => {
})

静态页面

在完善了主题之后,只需要将路由中所有注册过的页面重新循环一遍,将 ejs 渲染成 html 保存成相应的文件即可,最后可以通过 CI 部署到指定的网站即可。

评论(6)