While False Blog

Comments

September 05, 2020

Where do comments live?

I built this blog with GatsbyJS, which is optimized for static content. It works great for everything that exists when I build the code and create another docker image. But now I want to add comments from my readers. Which of course aren’t static and don’t exist on compile-time. So it seems GatsbyJS would not be the right tool for the job.

Luckily, GatsbyJS is expandable. There even is a guide on how to integrate comments in a blog on the gatsby website itself. But it assumes you just go and use some external service like disqus (although it does mention several alternatives). I didn’t want to outsource that, the whole point of this blog is to run things myself and learn from that.

What I found was Commento. It focusses around privacy and can be self-hosted instead of using an external service. It even has docker support. I quickly set up my very own instance on my server:

docker run -d --name blog-commento \
  -e "COMMENTO_ORIGIN=https://comments.while-false.de" \
  -e "COMMENTO_POSTGRES=postgres://commentoDbUser:SuperSecretPassword@db_postgres/commento?sslmode=disable" \
  registry.gitlab.com/commento/commento

(In reality, I use a few more parameters and steps required for my specific hosting setup, which I will explain in a future post)

So my blog itself can still be static and throught the magic of gatsby’s automatic optimization blazing fast, while the dynamic comments are handled by an external server, which I can fully control as I host it myself.

Include the comments in the blog

Next, I followed the documentation for commento and registered the blog on my commento instance. Easy.

Now to the tricky part. The static Gatsby.js website must embed the dynamic comments from the commento server. Again, I am lucky and found that someone already did exactly that. With some small tweaks, this is what I use:

import React, { useEffect } from 'react';

/**
 * Helper to add scripts to the page.
 * @param {string} src The source path for the script to insert.
 * @param {string} id The unique identifier for the script element to insert.
 * @param {HTMLElement} parentElement The DOM element to insert the script into.
 */
const insertScript = (src, id, parentElement) => {
  const script = window.document.createElement('script');
  script.async = true;
  script.src = src;
  script.id = id;
  parentElement.appendChild(script);
  return script;
};

/**
 * Helper to remove scripts from the page.
 * @param {string} id The unique identifier for the script element to remove.
 * @param {HTMLElement} parentElement The DOM element to remove the script from
 */
const removeScript = (id, parentElement) => {
  const script = window.document.getElementById(id);
  if (script) {
    parentElement.removeChild(script);
  }
};


const Commento = ({ id }) => {
  useEffect(() => {
    // If there's no window there's nothing to do
    if (!window) {
      return;
    }
    const { document } = window;
    // In case the #commento container exists, the commento script can be added
    if (document.getElementById('commento')) {
      insertScript('https://comments.while-false.de/js/commento.js', 'commento-script', document.body);
    }
    // Cleanup; remove the script from the page
    return () => removeScript('commento-script', document.body);
  }, [id]);
  return <div id="commento" />;
};

export default Commento;

This component itself is evaluated at runtime (it uses useEffect, which gatsby understands as non-static). It dynamically loads the scripts required by commento. The commento component is then included in my default blog-post template component by adding the line <Commento id={this.props.slug} />. The slug is the part of the URL after the hostname, i.e. 004-comments/ for this page. Thus, commento differentiates which comment belongs to which page.

Now, users can register and directly comment or comment anonymously with a required moderator review (which is me). Also, markdown, up- and downvoting, sorting, sticky, replies and moderation tools are included. Give it a try, I’d love to hear from you!

In the next few days I will tinker around with commento’s settings for moderation notification emails, custom styling and comment analytics (number of views and number of comments).


Written by Stephan Dörfler who lives and works in Germany trying to build useful things.

Comments