Intégrez les commentaires de Discourse dans votre application mono-page

Lorsque vous essayez d’implémenter [1] dans votre application monopage (SPA) qui ne fournit pas de pages rendues côté serveur, vous rencontrerez des problèmes, voir : [2]

Après quelques expérimentations, j’aimerais vous présenter l’approche suivante. L’exemple est en Vue.js, mais il peut être facilement adapté à d’autres frameworks/bibliothèques.

Remarque : J’utiliserai le terme articles de blog là où une section de commentaires Discourse devrait être intégrée. Mais cela peut bien sûr aussi signifier des pages individuelles sur votre site.

1. Les problèmes de [1]

1.1. javascripts/embed.js ne peut pas fonctionner avec du contenu rendu côté client

L’extrait \u003cscript\u003e...\u003c/script\u003e que l’on vous dit dans [1] d’insérer dans votre HTML ne fera donc pas partie de l’implémentation que nous abordons ici. Nous utiliserons certains éléments de javascripts/embed.js fournis par votre instance Discourse comme fonctions au sein de notre SPA.

1.2. Discourse ne peut pas analyser le contenu rendu côté client

Discourse crée automatiquement des sujets pour chaque article de blog et essaie d’accéder à l’URL d’origine (d’un article de blog) pour déterminer le titre et le contenu. Cela échoue avec une SPA, car Discourse obtiendra la partie sans JavaScript, par exemple Nous sommes désolés mais ce site ne fonctionne pas correctement sans JavaScript activé. Veuillez l'activer pour continuer.

Nous utiliserons le plugin RSS Polling pour fournir les données nécessaires et créer les sujets pour nous.

2. L’implémentation

2.1 RSS Polling et le flux RSS/Atom

Créez un point de terminaison sur votre site qui fournit un flux RSS ou Atom pour le plugin RSS Polling. Ce point de terminaison peut être soit un fichier statique formaté en XML, soit une fonction côté serveur fournissant le contenu formaté en XML, exemple :

URL : https://mysite.com/blog.atom

Contenu :

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>Articles de blog de Mon Site</title>
  <link href="https://mysite.com/blog/"/>
  <updated>2022-07-03T09:02:48.721Z</updated>
  <id>urn:uuid:790c1857-b968-49cc-9fbd-bf7afe3552c2</id>

  <entry>
    <title>Un article sur la technologie</title>
    <author>
      <name>Votre Nom Ici</name>
    </author>
    <link href="https://mysite.com/blog/un-article-sur-la-technologie"/>
    <id>urn:uuid:f6cc13e4-d2eb-4385-af28-c867a94f48dc</id>
    <published>2022-07-03T00:00:00Z</published>
    <updated>2022-07-03T00:00:00Z</updated>
    <summary>Discutons de technologie dans cet article.</summary>
  </entry>

</feed>

Installez le plugin RSS Polling pour Discourse conformément à [3] (Discourse hébergé) ou [4] (auto-hébergé)

Paramètres recommandés pour RSS Polling dans Admin → Paramètres → Plugins :

Clé Valeur
rss polling enabled true
rss polling frequency 10 (soit 10 minutes)

Ajoutez un nouveau flux dans la configuration du plugin RSS Polling à Admin → Plugins → RSS Polling

Configurez-le conformément à [3] :

Clé Valeur
URL https://mysite.com/blog.atom
Filtre de catégorie \u003cceci est optionnel\u003e
Auteur \u003cDéfinir un auteur pour les sujets générés automatiquement\u003e
Catégorie \u003cDéfinir la/les catégorie(s) où les sujets générés automatiquement seront publiés\u003e
Tags \u003cceci est optionnel\u003e

2.2 Configuration du routeur SPA

Discourse utilise la dernière partie du chemin d’URL comme identifiant pour un article de blog individuel.

Exemples :

https://mysite.com/blog/un-article-sur-la-technologie
https://mysite.com/blog/un-autre-article-sur-les-chats

Configurez votre routeur SPA en conséquence, de sorte que les articles de blog individuels correspondent à des URL individuelles.

Aussi : Discourse fournira un lien de retour vers l’article de blog individuel, il est donc bon pour l’expérience utilisateur que lorsque vous cliquez dessus, votre site affiche l’article réel.

2.3 Le composant Article

Comme indiqué précédemment, nous ne pouvons pas utiliser l’approche avec le \u003cscript\u003e\u003c/script\u003e de [1]. Nous implémentons donc l’iframe et certaines fonctions de javascripts/embed.js dans notre composant :

Article.vue

Choses que vous devriez modifier :

Élément Description
#VOTRE-URL-DISCOURSE# l’URL de votre instance Discourse, par exemple discourse.mysite.com)
#VOTRE-URL-SITE# l’URL de votre site, par exemple mysite.com éventuellement aussi %2Fblog%2F si le chemin de vos articles de blog n’est pas /blog/
<template>
  <div id="article">

    <!-- votre article formaté ici -->

    <iframe
      v-if="slug"
      v-bind:src="`https://#VOTRE-URL-DISCOURSE#/embed/comments?embed_url=https%3A%2F%2F#VOTRE-URL-SITE#%2Fblog%2F${slug}%2F`"
      id="discourse-embed-frame"
      width="100%"
      v-bind:height="`${iframeHeight}px`"
      frameborder="0"
      scrolling="no"
      referrerpolicy="no-referrer-when-downgrade"
    />
  </div>
</template>

<script>
export default {
  data: () => ({
    slug: null,     // le slug de l'article de blog, par exemple "un-article-sur-la-technologie" alors que la route est "https://mysite.com/blog/un-article-sur-la-technologie"
    iframeHeight: 0 // Discourse nous indiquera la hauteur exacte de l'iframe (voir : méthode receiveMessage)
  }),

  methods: {
    // communication iframe
    receiveMessage(event) {
      if (!event) {
        return;
      }
      if (!(event.origin || "").includes("#VOTRE-URL-DISCOURSE#")) {
        return;
      }

      if (event.data) {
        if (event.data.type === "discourse-resize" && event.data.height) {
          this.iframeHeight = +event.data.height;
        }

        if (event.data.type === "discourse-scroll" && event.data.top) {
          // trouver le décalage de l'iframe
          const destY = this.findPosY(this.$refs["discourse-embed-frame"]) + event.data.top;
          window.scrollTo(0, destY);
        }
      }
    },

    // Merci http://amendsoft-javascript.blogspot.ca/2010/04/find-x-and-y-coordinate-of-html-control.html
    findPosY(obj) {
      var top = 0;
      if (obj.offsetParent) {
        while (1) {
          top += obj.offsetTop;
          if (!obj.offsetParent) break;
          obj = obj.offsetParent;
        }
      } else if (obj.y) {
        top += obj.y;
      }
      return top;
    }
  },

  async created() {
    this.slug = this.$router.currentRoute.path.split("/")[2];
  },

  mounted() {
    window.addEventListener("message", this.receiveMessage);
  },
  beforeDestroy() {
    window.removeEventListener("message", this.receiveMessage);
  }
}
</script>

2.4 Configuration de l’intégration Discourse

Maintenant que le polling du flux RSS/Atom est en place et l’implémentation sur votre site, nous pouvons enfin configurer l’intégration sur l’instance Discourse.

Allez dans Admin → Personnaliser → Intégration et ajoutez un hôte :

Clé Valeur
Hôtes autorisés votre URL de base de site\u003e par exemple “mysite.com
Nom de classe nom de classe optionnel pour le style
Liste d’autorisation de chemin par exemple “/blog/.*”
Publier dans la catégorie même catégorie que celle configurée dans la catégorie RSS Polling

3. Remarques finales

Le polling du flux RSS/Atom ainsi que Discourse lui-même créeront un nouveau sujet s’il n’existe pas pour l’article de blog individuel. Assurez-vous que le polling du flux RSS/Atom se fasse en premier (c’est-à-dire attendez que le sujet soit créé avant de visiter l’article de blog sur votre site).

Raison : Discourse ne peut pas analyser le titre et le résumé, donc le sujet serait mysite.com avec le résumé étant Nous sommes désolés, mais ce site ne fonctionne pas sans JavaScript. :wink:

Si pour une raison quelconque Discourse est arrivé en premier, vous pouvez simplement supprimer le sujet et attendre que le flux RSS/Atom soit pris en compte.

Cordialement

– MK2k

2 « J'aime »