Incorpore comentários do Discourse em seu aplicativo de página única

Ao tentar implementar [1] em sua Single Page Application (SPA) que não fornece páginas renderizadas no lado do servidor, você eventualmente encontrará problemas, veja: [2]

Portanto, após um pouco de experimentação, gostaria de apresentar a seguinte abordagem. O exemplo está em Vue.js, no entanto, pode ser facilmente adaptado para outros frameworks/libs.

Observação: Usarei o termo posts de blog onde uma seção de comentários do Discourse deve ser incorporada. Mas, claro, isso também pode significar páginas individuais em seu site.

1. Os problemas em [1]

1.1. javascripts/embed.js não pode funcionar com conteúdo renderizado no lado do cliente

O snippet <script>...</script> que é informado em [1] para inserir em seu HTML, portanto, não fará parte da implementação que estamos abordando aqui. Utilizaremos alguns trechos de javascripts/embed.js fornecidos por sua instância do Discourse como funções dentro de nossa SPA.

1.2. O Discourse não pode raspar conteúdo renderizado no lado do cliente

O Discourse cria automaticamente tópicos para cada post de blog e tenta acessar a URL original (de um post de blog) para determinar o título e o conteúdo. Isso falha com uma SPA, porque o Discourse obterá a parte sem JavaScript, por exemplo, Lamentamos, mas este site não funciona corretamente sem JavaScript ativado. Por favor, ative-o para continuar.

Utilizaremos o plugin RSS Polling para fornecer os dados necessários e criar os tópicos para nós.

2. A implementação

2.1 RSS Polling e o feed RSS/Atom

Crie um endpoint em seu site que forneça um feed RSS ou Atom para o plugin RSS Polling. Este endpoint pode ser apenas um arquivo estático formatado em XML ou uma função do lado do servidor fornecendo o conteúdo formatado em XML, exemplo:

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

Conteúdo:

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

  <title>Posts do Blog do Meu Site</title>
  <link href="https://meusite.com/blog/"/>
  <updated>2022-07-03T09:02:48.721Z</updated>
  <id>urn:uuid:790c1857-b968-49cc-9fbd-bf7afe3552c2</id>

  <entry>
    <title>Um Artigo sobre Tecnologia</title>
    <author>
      <name>Seu Nome Aqui</name>
    </author>
    <link href="https://meusite.com/blog/um-artigo-sobre-tecnologia"/>
    <id>urn:uuid:f6cc13e4-d2eb-4385-af28-c867a94f48dc</id>
    <published>2022-07-03T00:00:00Z</published>
    <updated>2022-07-03T00:00:00Z</updated>
    <summary>Vamos discutir um pouco de tecnologia neste artigo.</summary>
  </entry>

</feed>

Instale o plugin RSS Polling para Discourse conforme [3] (Discourse hospedado) ou [4] (auto-hospedado)

Configurações Recomendadas para RSS Polling em Admin → Configurações → Plugins:

Chave Valor
rss polling enabled true
rss polling frequency 10 (ou seja, 10 minutos)

Adicione um novo feed na configuração do plugin RSS Polling em Admin → Plugins → RSS Polling

Configure-o conforme [3]:

Chave Valor
URL https://meusite.com/blog.atom
Filtro de Categoria <isso é opcional>
Autor <defina um autor dos tópicos gerados automaticamente>
Categoria <defina a(s) categoria(s) onde os tópicos gerados automaticamente serão postados>
Tags <isso é opcional>

2.2 Configuração do Roteador SPA

O Discourse usa a última parte do caminho da URL como identificador para um post de blog individual.

Exemplos:

https://meusite.com/blog/um-artigo-sobre-tecnologia
https://meusite.com/blog/outro-artigo-sobre-gatos

Configure seu roteador SPA de acordo, para que posts de blog individuais correspondam a URLs individuais.

Além disso: o Discourse fornecerá um link de volta para o post de blog individual, portanto, é uma boa experiência do usuário que, ao clicar, seu site exiba o artigo real.

2.3 O Componente Artigo

Como dito antes, não podemos usar a abordagem com o <script></script> de [1]. Então implementamos o iframe e algumas funções de javascripts/embed.js em nosso componente:

Article.vue

Coisas que você deve editar:

item descrição
#SEU-URL-DISCOURSE# a URL de sua instância do Discourse, por exemplo, discourse.meusite.com)
#SEU-URL-SITE# a URL de seu site, por exemplo, meusite.com possivelmente também %2Fblog%2F se o caminho dos posts do seu blog não for /blog/
<template>
  <div id="article">

    <!-- seu artigo formatado aqui -->

    <iframe
      v-if="slug"
      v-bind:src="`https://#SEU-URL-DISCOURSE#/embed/comments?embed_url=https%3A%2F%2F#SEU-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,     // o slug do post de blog, por exemplo, "um-artigo-sobre-tecnologia" enquanto a rota é "https://meusite.com/blog/um-artigo-sobre-tecnologia"
    iframeHeight: 0 // O Discourse nos dirá a altura exata do iframe (veja: método receiveMessage)
  }),

  methods: {
    // comunicação iframe
    receiveMessage(event) {
      if (!event) {
        return;
      }
      if (!(event.origin || "").includes("#SEU-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) {
          // encontrar o offset do iframe
          const destY = this.findPosY(this.$refs["discourse-embed-frame"]) + event.data.top;
          window.scrollTo(0, destY);
        }
      }
    },

    // Obrigado 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 Configuração de Incorporação do Discourse

Agora, com o polling do feed RSS/Atom em vigor e a implementação em seu site, podemos finalmente configurar a incorporação na instância do Discourse.

Vá para Admin → Personalizar → Incorporação e adicione um host:

Chave Valor
Hosts Permitidos URL base do seu site> por exemplo, “meusite.com
Nome da Classe nome de classe opcional para estilização
Listagem de Caminhos Permitidos por exemplo, “/blog/.*”
Postar para Categoria mesma categoria configurada em Categoria de RSS Polling

3. Observações Finais

O polling do feed RSS/Atom, bem como o próprio Discourse, criará um novo tópico se ele não existir para o post de blog individual. Certifique-se de que o polling do feed RSS/Atom ocorra primeiro (ou seja, espere até que o tópico seja criado antes de visitar o post de blog em seu site).

Motivo: O Discourse não consegue raspar o título e o resumo, então o tópico seria meusite.com com o resumo sendo Lamentamos, mas este site não funciona sem JavaScript. :wink:

Se por algum motivo o Discourse vier primeiro, você pode simplesmente excluir o tópico e esperar até que o feed RSS/Atom entre em vigor.

Saudações
– MK2k

2 curtidas