greatghoul / greatghoul.github.io

个人博客
https://anl.gg
2 stars 0 forks source link

使用 Github Issues 写独立博客 #238

Open greatghoul opened 10 months ago

greatghoul commented 10 months ago

slug: github-issues-as-blog date: 2021-08-21

01 又迁移博客了

我之前使用过 issues 写博客一段时间,那是一个 public 的 github repo, 借助于 github 的 markdown 编辑器,写作编程了一件很有趣的事情,也着实写了一些文章。不过因为 issues 本身的限制,我没有一个独立的域名,因为受到一个独立博客群组的“荼毒”,我有购买了域名,搞起了独立博客的勾当。

自己用 Ruby on Rails 写了个博客程序,使用 Basecamp 的 Trix Editor 作为编辑器,虽然程序搭建起来了,也运行良好,但是我发现自己没有那么多时间去定制那个编辑器来实现一些想要的功能。而且托管一个 rails 应用,好歹也需要一个 vps, 得花钱呀。我使用的 AWS,这东西真的不便宜。

于是我一天在看 Next.js 的时候,脑袋一热,就用 Next.js 来写了一个博客程序,使用 Github Issues 作为博客的数据库,程序部署在 Vercel 上面,可以自动部署,免费,还自带 HTTPS,一切近乎完美,因为在开发电鸭社区网站时得到的锻炼,整个过程也就花了四五个小时。

03 优点和缺点

目前我的这个方案:使用私有 Github Issues 作为博客,使用 Vercel 托管博客程序,优点还是很明显的

缺点也肯定有,但是不致命

04 实现原理

要运行这个博客,你需要

博客是一个简单的 Next.js 项目,直接调用 Github API,然后进行服务端渲染,一气呵成。因为 Github API 匿名调用的话,限额非常低,所以最好申请一个 Personal Access Token,差不多就够用了。

为了安全性,Token 可以维护到 Vercel 环境变量中,并使用加密类型存储

image

image

我的 Next.js 程序中,使用到了如下的 JavaScript 库,用于

我给 Issues 设置了一个保留标签 "0_Published",用于标识文章是否已经发布了,用 YAML Front Matter 来解决 Issues 创建时间和真实发布时间不一致的情况。

image

给便签加前缀 "0_" 是为了让它始终保持在第一个,方便选择。

下面一段代码,是读取和把 Issue 处理为文章数据的结构的代码,仅供参考,你可以根据自己的需求,定制自己的代码。

// utils/github.js

import { Octokit } from '@octokit/rest'
import frontMatter from 'front-matter'
import marked from 'marked'
import truncate from 'truncate-html'

const LABEL_PUBLISHED = '0_Published'
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN })
const repo = {
  owner: process.env.GITHUB_OWNER,
  repo:  process.env.GITHUB_REPO
}

function issueToPost (issue) {
  const { attributes, body } = frontMatter(issue.body)
  const content = marked(body)
  const attrs = JSON.parse(JSON.stringify(attributes))

  return {
    id: issue.number,
    title: issue.title,
    author: issue.user,
    labels: issue.labels.filter(x => x.name !== LABEL_PUBLISHED),
    published: issue.labels.filter(x => x.name === LABEL_PUBLISHED).length > 0,
    published_at: attrs.date || issue.created_at,
    attrs: attrs,
    content: content,
    brief: truncate(content, {
      length: 250,
      stripTags: true,
      excludes: ['img', 'pre']
    })
  }
}

export async function getRecentPosts (page) {
  return octokit.rest.issues.listForRepo({
    ...repo,
    labels: LABEL_PUBLISHED,
    sort: 'created',
    direction: 'desc',
    per_page: 10,
    page: page
  }).then(resp => resp.data.map(issueToPost))
}

export async function getPost (id) {
  return octokit.rest.issues.get({
    ...repo,
    issue_number: id
  }).then(resp => issueToPost(resp.data))
}

05 Vercel

Vercel 是一个非常良心的服务,可以让你免费的部署和托管前端应用,甚至贴心的配备了 https,省了很多很多事情,每次要更新应用时,你只需要 push 代码就可以了,不需要考虑维护 node 环境,build,nginx 等等烦恼的事情。

以前因为对前端不熟悉,部署 js 应用还要用 capstrano 这样的大家伙,现在好了,一切都是自动化了。

image

Vercel 虽然比较妙,但是也带来了一些副作用,你必须把域名 nameserver 迁到 vercel 上面来,这就导致这个域名几乎只能用来跑 vercel 的服务了,因为 vercel 的 DNS 管理,是一个非常简化的版本,像 URL Redirect 这样的操作,都是不支持的,就连 A 记录到指定 IP,也有问题。但好处是,有自动的 HTTPS 了,不需要再去维护证书。