Adding comments to a Svelte site using Cusdis

Yet another 'how to do comments' blog post
posted on 2022-02-02

#svelte

#comments

👇See an exampe at the bottom of this page.👇

This tutorial is for a [Svelte + Sapper] site, but code examples can easily be adapted to other frameworks.

At the end of this tutorial you’ll have:

  • Comments section on every page of your Svelte site
  • Dashboard with comments moderation
  • (optional) Email notifications when someone leaves a comment
...for free!


Pre-requisite:

  1. Self-host Cusdis.
  2. Get yourself a database - the free Heroku Postgres will do.



Adding Cusdis to Svelte site

To add comments support on any page of your static site, you need to add the Cusdis element in your _layout.svelte template - this is where the comments secion iframe will be loaded into. This is also how we pass our config to the SDK (it will read from this element).

<main>
  <slot />
  <!-- Only render the element on the client, not the server -->
  {#if isClient && pageId}
    <div
      bind:this={cusdisElement}
      id="cusdis_thread"
      data-host="<YOUR CUSDIS URL HERE>"
      data-app-id="<YOUR CUSDIS APP ID HERE>"
      data-page-id={pageId}
      data-page-url={window.location.href}
      data-page-title={document.title}
      data-theme='dark'
    />
  {/if}
</main>

For data-app-id, you can grab the Cusdis app ID from the settings in the Cusdis dashboard.

Now let’s define those variables:

let isClient = false; # for ignoring server-side rendering
let pageId; # for linking comments to the current page
let cusdisElement; # The comments frame itself

Dynamic pageId

And now let’s write a function that will set the pageId. This could be a unique ID, or based on the URL. I used the URL path (without the domain) as the pageId. Eg. if the current URL is https://slavbasharov.com/blog/adding-comments-to-static-site the pageId is blog/adding-comments-to-static-site

let pageId;
const setPageId = () => {
    // Get the page from the URL
    if (typeof window !== "undefined") {
        if (window.location.href.includes("https://slavbasharov.com")) {
        pageId = window.location.href
            .split("https://slavbasharov.com")
            .filter((a) => a.length && a !== "/");
        } else if (window.location.href.includes("http://localhost:3000")) {
        pageId = window.location.href
            .split("http://localhost:3000")
            .filter((a) => a.length && a !== "/");
        }

        // Default to home
        if (pageId.length) {
            pageId = pageId[0];
        } else {
            pageId = "home";
        }

        // Remove leading /
        if (pageId && pageId.charAt(0) === "/") {
            pageId = pageId.slice(1);
        }
    }
};

We need to update the pageId automatically whenever the route changes. To do this, we import the page store which will fire on update:

import { stores } from "@sapper/app";

const { page } = stores();

We can now perform the update in two steps:

  • Update the page ID on route change
  • Tell the SDK to use the new page ID
  /*
  Listen for page changes and set the current page ID to pass into the SDK.
  */
  $: {
    if (typeof window !== "undefined") {
      if ($page.path) {
        setPageId();
      }
    }
  }

  /*
  Re-initialize the SDK when the page id attribute is changed in the element. 
  */
  onMount(() => {
    new MutationObserver(initCusdis).observe(cusdisElement, {
      attributeFilter: ["data-page-id"],
    });

    setPageId();
  });

  if (typeof window !== "undefined") {
    isClient = true;
  }

Hope that was helpful! Let me know in the comments if anything in this article is wrong or doesn’t work as expected. You are also welcome to say nice things.