JAMstack Comments

JAMstack sites are often seen as being static. A more accurate mental model for them would be that they are sites which have the ability to be hosted statically. The difference might seem semantic, but thanks to the rise of many tools and services which simplify running a build and deploying to static hosting infrastructure, such sites can feel much fresher and dynamic than you might imagine, while still capable of being served from static hosting infrastructure, with all the benefits that brings.

A feature often used as an example of why a site cannot be hosted statically is comments. A comments engine needs to handle submissions, allow for moderation, and is by its very nature, "dynamic".

Comment systems are generally thought of as quite dynamic content

Thanks to the growing ecosystem of tools available for JAMstack sites, there are solutions to this. Let's look at an example which you could use on your own site, which:

  • Does not depend on client-side JavaScript
  • Could work with any static site generator
  • Includes moderation
  • Sends notifications when new comments need moderating
  • Bakes the comments into your site, so that they load quickly and appear in searches

This example makes use of some of the features of Netlify, a platform for automating, deploying and hosting web projects, but many of the principles could be used with other platforms.

You can see the example site here.

Stashing our content

We'll create 2 forms to receive all of our comments at the different stages of their journey from commenter to content. When Netlify sees a <form>, it creates a unique data store for the data the form collects. We'll make great use of that.

  • Form 1) A queue to hold all of the new comment submissions. In other words, a store to hold all comments awaiting moderation.
  • Form 2) Contains all approved comments.

The act of moderation will be somebody looking at each new submission and deciding, "yep!" or "nope!". Those that get nope-d will be deleted from the queue. Those that are approved will be posted over to the approved comments form.

All of the comments in the approved comments form are used by our static site generator in subsequent site builds thanks to the API access Netlify gives to the submissions in our forms.

The comment form

Each page includes an HTML <form>. By adding the boolean attribute of netlify to any HTML form element in your site, Netlify will automatically generate an API for your form, and gathers all of the submissions to it for you. You'll also be able to access the submissions via that API later. Handy!

The comments <form> on each page will look a lot like this (some classes and extra copy omitted for clarity):

<form netlify name="comments-queue" action="/thanks">
  <input name="path" type="hidden" value="{{ page.url }}">
  <p>
    <label for="name">Your name</label>
    <input type="text" name="name" id="name">
  </p>
  <p>
    <label for="email">Your email</label>
    <input type="email" name="email" id="email">
  </p>
  <p>
    <label for="comment">Your comment</label>
    <textarea name="comment" id="comment"></textarea>
  </p>
  <p>
    <button type="submit">Post your comment</button>
  </p>
</form>

You'll may notice that the form also includes a type="hidden" field to let us know which page on the site this comment is for. Our static site generator populates that for us when the site is generated, and well use it later when deciding which comments should be shown on which page.

Submissions and notifications

When a new comment is posted via the comment form, Netlify not only stashes that for us, but can also send a notification. That could be:

  • an email
  • a Slack notification
  • a webhook of our choosing.

These give us the chance to automate things a little.

New submissions result in a notification being posted to Slack. We'll get to see what was submitted and to which page right there in our Slack client.

To make things extra slick, we can massage that notification a little to include some action buttons. One button to delete the comment, one to approve it. Approving a new comment from a Slack notification on your phone while riding the bus feels good.

We can't make those buttons work without running a little bit of logic which, we can do in a Lambda function. Netlify recently added support for Lambda functions too, making the process of writing and deploying Lambdas part of the same deployment process. You'll not need to go rummaging around in Amazon's AWS configuration settings.

We'll use one Lambda function to add some buttons to our Slack notification, and another Lambda function to handle the actions of clicking either of those buttons.

Bring the comments into the site

With a freshly approved comment being posted to our approved comments form, we are back to using the submission event triggers that Netlify provides. Every time something is posted to the approved comments form, we'll want to include it in the site, so we have Netlify automatically rebuild and deploy our site.

Most static site generators have some notion of data files. Jekyll uses files in a [_data] directory, Hugo has a similar data directory. This example is using Eleventy as its static site generator which has a similar concept. We'll make use of this.

Each time we run our site build, whether in our local development environment or within Netlify through their automated builds, the first step is to pull all of our external data into local data files which our SSG can then use. We do that with a Gulp task.

Armed with a `comments.json` file which we have populated from a call to Netlify's form submission API which grabbed all of our approved comments, our SSG can now build the site as normal and bake the correct comments right into the HTML of our pages.

Some benefits

Well that was fun, but why bother?

Yes, you could use something like Disqus to add comments to a statically hosted site via a few lines of JavaScript. But that adds an external JavaScript dependency and results in the comments about your content living far away from the content itself. And it's only available once the JavaScript has loaded, pulled in the data and then injected it into your site.

Whereas this method results in comments that are baked right into the content of your site. They'll show up in searches on Google and they will load as part of your site without the need for any client-side JavaScript.

Even better, they'll be available for you to commit right into your code repository with the rest of your content, giving you more peace of mind and portability in the future.

The example site and all of its code are available to explore. You can try submitting comments if you like (although poor old Phil will need to moderate any comments on this example site before they appear, but that will just make him feel loved).

Better still, you can clone this example and deploy your own version to Netlify with just a few clicks. The example site explains how.

Just show me behind the scenes right now!

If you'd want to take a look at how things behave for the moderator of a site using this system without grabbing a copy of your own, this short video will walk through a comment being made, moderated and incorporated into the site.