Al intentar implementar [1] en tu aplicación de página única (SPA) que no proporciona páginas renderizadas del lado del servidor, eventualmente encontrarás problemas, consulta: [2]
Así que, después de un poco de experimentación, me gustaría presentar el siguiente enfoque. El ejemplo está en Vue.js, sin embargo, se puede adaptar fácilmente a otros frameworks/librerías.
Nota: Usaré el término entradas del blog donde se deba incrustar una sección de comentarios de Discourse. Pero, por supuesto, esto también puede significar páginas individuales en tu sitio.
1. Los problemas en [1]
1.1. javascripts/embed.js no puede funcionar con contenido renderizado del lado del cliente
El fragmento <script>...</script> que se te indica en [1] insertar en tu HTML, por lo tanto, no formará parte de la implementación que estamos abordando aquí. Utilizaremos algunas partes de javascripts/embed.js proporcionadas por tu instancia de Discourse como funciones dentro de nuestra SPA.
1.2. Discourse no puede rastrear contenido renderizado del lado del cliente
Discourse crea automáticamente temas para cada entrada del blog e intenta acceder a la URL original (de una entrada del blog) para determinar el título y el contenido. Esto falla con una SPA, porque Discourse obtendrá la parte sin JavaScript, por ejemplo, Lamentamos que este sitio no funcione correctamente sin JavaScript habilitado. Habilítelo para continuar.
Utilizaremos el plugin RSS Polling para proporcionar los datos necesarios y crear los temas por nosotros.
2. La implementación
2.1 RSS Polling y el feed RSS/Atom
Crea un endpoint en tu sitio que proporcione un feed RSS o Atom para el plugin RSS Polling. Este endpoint puede ser simplemente un archivo estático con formato XML o una función del lado del servidor que proporcione el contenido con formato XML, ejemplo:
URL: https://misitio.com/blog.atom
Contenido:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Entradas del Blog de Mi Sitio</title>
<link href="https://misitio.com/blog/"/>
<updated>2022-07-03T09:02:48.721Z</updated>
<id>urn:uuid:790c1857-b968-49cc-9fbd-bf7afe3552c2</id>
<entry>
<title>Un Artículo sobre Tecnología</title>
<author>
<name>Tu Nombre Aquí</name>
</author>
<link href="https://misitio.com/blog/un-articulo-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>Discutamos algo de tecnología en este artículo.</summary>
</entry>
</feed>
Instala el plugin RSS Polling para Discourse según [3] (Discourse alojado) o [4] (autoalojado)
Configuraciones recomendadas para RSS Polling en Admin → Configuración → Plugins:
| Clave | Valor |
|---|---|
| rss polling enabled | true |
| rss polling frequency | 10 (es decir, 10 minutos) |
Agrega un nuevo feed en la configuración del plugin RSS Polling en Admin → Plugins → RSS Polling
Configúralo según [3]:
| Clave | Valor |
|---|---|
| URL | https://misitio.com/blog.atom |
| Category Filter | <esto es opcional> |
| Author | <define un autor de los temas generados automáticamente> |
| Category | <define la/s categoría/s donde se publicarán los temas generados automáticamente> |
| Tags | <esto es opcional> |
2.2 Configuración del Router de la SPA
Discourse utiliza la última parte de la ruta de la URL como identificador para una entrada de blog individual.
Ejemplos:
https://misitio.com/blog/un-articulo-sobre-tecnologia
https://misitio.com/blog/otro-articulo-sobre-gatos
Configura tu router SPA en consecuencia, para que las entradas de blog individuales correspondan con URLs individuales.
Además: Discourse proporcionará un enlace de regreso a la entrada del blog individual, por lo que es una buena experiencia de usuario que, al hacer clic, tu sitio muestre el artículo real.
2.3 El Componente Artículo
Como se mencionó anteriormente, no podemos usar el enfoque con el <script></script> de [1]. Así que implementamos el iframe y algunas funciones de javascripts/embed.js en nuestro componente:
Article.vue
Cosas que deberías editar:
| Ítem | Descripción |
|---|---|
| #YOUR-DISCOURSE-URL# | la URL de tu instancia de Discourse, por ejemplo, discourse.misitio.com) |
| #YOUR-SITE-URL# | la URL de tu sitio, por ejemplo, misitio.com posiblemente también %2Fblog%2F si la ruta de las entradas de tu blog no es /blog/ |
<template>
<div id="article">
<!-- tu artículo formateado aquí -->
<iframe
v-if="slug"
v-bind:src="`https://#YOUR-DISCOURSE-URL#/embed/comments?embed_url=https%3A%2F%2F#YOUR-SITE-URL#%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, // el slug de la entrada del blog, por ejemplo, "un-articulo-sobre-tecnologia" mientras la ruta es "https://misitio.com/blog/un-articulo-sobre-tecnologia"
iframeHeight: 0 // Discourse nos dirá la altura exacta del iframe (ver: método receiveMessage)
}),
methods: {
// comunicación iframe
receiveMessage(event) {
if (!event) {
return;
}
if (!(event.origin || "").includes("#YOUR-DISCOURSE-URL#")) {
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 el offset del iframe
const destY = this.findPosY(this.$refs["discourse-embed-frame"]) + event.data.top;
window.scrollTo(0, destY);
}
}
},
// Gracias 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 Configuración de Incrustación de Discourse
Ahora, con el sondeo del feed RSS/Atom en funcionamiento y la implementación en tu sitio, finalmente podemos configurar la incrustación en la instancia de Discourse.
Ve a Admin → Personalizar → Incrustación y agrega un host:
| Clave | Valor |
|---|---|
| Allowed Hosts | la URL base de tu sitio> por ejemplo, “misitio.com” |
| Class Name | nombre de clase opcional para estilizar |
| Path Allowlist | por ejemplo, “/blog/.*” |
| Post to Category | la misma categoría que se configuró en la Categoría de RSS Polling |
3. Comentarios Finales
El sondeo del feed RSS/Atom, así como Discourse mismo, crearán un nuevo tema si no existe para la entrada de blog individual. Asegúrate de que el sondeo del feed RSS/Atom ocurra primero (es decir, espera hasta que se cree el tema antes de visitar la entrada del blog en tu sitio).
Razón: Discourse no puede rastrear el título y el resumen, por lo que el tema sería misitio.com con el resumen siendo Lamentamos que este sitio no funcione sin javascript. ![]()
Si por alguna razón Discourse se adelantó, puedes simplemente eliminar el tema y esperar a que el feed RSS/Atom se active.
Saludos
– MK2k