I decided that I want to have my own blogging platform that I feel comfortable writing on. It should have these properties:

  • Simple and clean.
  • Both public and private spaces. Sometimes I don't really want to share a post with the public but only people who are interested in a specific topic - so a private space is necessary.
  • Interpretable data. My content should belong to myself, be stored in a human-readable structure and interact well with existing tools. Relational database is an option, but I like Git more.
  • Topic-centered, or "idea-centered" content organization.
  • Collaboratable. When I work on ideas with my friends we want to share a common place to write.

Although maintaining my own infrastructure is fun, its complexity mismatches with the goal to keep the system simple. I would have to deal with infrastructure security/stability/scalability issues myself, and that's time-consuming work.

Fortunately this year is 2021 and we have nice serverless and SaaS platforms. I decided to use as many of them as possible:

  • Hosting: Frontend on Cloudflare Workers, submission control service on AWS Lambda.

  • Storage: GitHub as the single source of truth for all online data, DynamoDB for content hold by the submission control service, and Workers KV for caching.

  • Discussions: Cusdis.

  • Email: Sendgrid for receiving and Mailgun for sending.

  • Profiles: Gravatar.

Managing content

To make a blogging platform useful there needs to be a way to add, edit and delete content, and the submission control service is my solution to the problem. Instead of building yet another Web CMS , why not just put together all the awesome things we already have?

  • Email works well as a control channel. Today's email clients are fairly good at sorting and classifying information, and existing applications integrate well with emails through attachments and sharing.
  • Markdown is a nice language for writing. It keeps you focused on the actual content instead of formatting, and there exists many awesome Markdown editors.

I use Typora and Taio to write in Markdown, and when I want to publish it's as simple as sending the .md file to topic-name@x.univalence.me. Then Sendgrid parses my email and notifies the submission control service on Lambda through a webhook.

The service then checks and renders the post, and replies with a link to the preview.

If the preview looks okay, I reply to the preview with /we publish. The service then commits the post: call the GitHub API to create a commit. After the commit is pushed a GitHub workflow is automatically triggered, notifies the frontend service on Workers to update its cache, and sends notification emails to subscribers.

The stack

  • marked is integrated to the submission control service to render Markdown content to HTML. The HTML is then rewritten on the edge to support features like preview spellchecking, link-to-reference conversions and LaTeX.
  • On the frontend custom CSS rules are applied to produce the visible output. The styles are heavily inspired by the wechat-format project!
  • The system is mostly implemented in TypeScript, and esbuild is used to build all the three JavaScript bundles for Workers, Lambda and Workflow.
  • Handlebars templates are precompiled into JavaScript and evaluated on the edge to build pages.
  • Rust and WebAssembly are used to process emails, validate input and minify pages.
  • LaTeX content is rendered through the Math API service.

Modern frontend?

I avoided using frontend JavaScript unless necessary. Pages will work with JavaScript disabled except these features:

  • Subscription. Confirmation emails can be used to spam people, so Recaptcha is used to verify that a real user is sending the subscription requests.
  • Code highlighting. This is implemented with highlight.js currently, but I want to render the highlights on server side eventually.
  • Discussions. I use Cusdis to manage comments and the service requires JavaScript.

Open Source?

The system is not yet open source, since it's a bit dirty - hardcoded strings, tightly coupled logic across Workers and Lambda, etc. I'm looking forward to making it open source when everything is ready!