При попытке внедрения [1] в ваше одностраничное приложение (SPA), которое не поддерживает серверный рендеринг страниц, вы неизбежно столкнётесь с проблемами, см.: [2]
Поэтому после некоторых экспериментов я хочу предложить следующий подход. Пример приведён для Vue.js, однако его можно легко адаптировать под другие фреймворки/библиотеки.
Примечание: Я буду использовать термин статьи блога, где должен быть встроен раздел комментариев Discourse. Но, конечно, это также могут быть отдельные страницы вашего сайта.
1. Проблемы в [1]
1.1. javascripts/embed.js не может работать с контентом, рендерящимся на стороне клиента
Фрагмент <script>...</script>, который предлагается в [1] вставить в ваш HTML, не будет частью реализации, к которой мы стремимся здесь. Мы будем использовать некоторые части javascripts/embed.js, предоставляемые вашим экземпляром Discourse, в качестве функций внутри нашего SPA.
1.2. Discourse не может парсить контент, рендерящийся на стороне клиента
Discourse автоматически создаёт темы для каждой статьи блога и пытается получить доступ к исходному URL (статьи блога), чтобы определить заголовок и содержимое. Это не работает с SPA, потому что Discourse получит часть без JavaScript, например: Нам очень жаль, но этот сайт не работает должным образом без включенного JavaScript. Пожалуйста, включите его, чтобы продолжить.
Мы будем использовать плагин RSS Polling для предоставления необходимых данных и создания тем за нас.
2. Реализация
2.1 RSS Polling и RSS/Atom-канал
Создайте конечную точку на вашем сайте, которая предоставляет RSS или Atom-канал для плагина RSS Polling. Эта конечная точка может быть либо просто статическим файлом в формате XML, либо функцией на стороне сервера, предоставляющей контент в формате XML, пример:
URL: https://mysite.com/blog.atom
Содержимое:
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Статьи блога моего сайта</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>Статья о технологиях</title>
<author>
<name>Ваше Имя Здесь</name>
</author>
<link href="https://mysite.com/blog/an-article-about-technology"/>
<id>urn:uuid:f6cc13e4-d2eb-4385-af28-c867a94f48dc</id>
<published>2022-07-03T00:00:00Z</published>
<updated>2022-07-03T00:00:00Z</updated>
<summary>Давайте обсудим некоторые технологии в этой статье.</summary>
</entry>
</feed>
Установите плагин RSS Polling для Discourse согласно инструкциям для [3] (Discourse в облаке) или [4] (самостоятельный хостинг)
Рекомендуемые настройки для RSS Polling в Администрирование → Настройки → Плагины:
| Ключ | Значение |
|---|---|
| rss polling enabled | true |
| rss polling frequency | 10 (т.е. 10 минут) |
Добавьте новый канал в конфигурации плагина RSS Polling в Администрирование → Плагины → RSS Polling
Настройте его согласно инструкциям для [3]:
| Ключ | Значение |
|---|---|
| URL | https://mysite.com/blog.atom |
| Фильтр по категории | <это необязательно> |
| Автор | <определите автора автоматически генерируемых тем> |
| Категория | <определите категорию/категории, где будут публиковаться автоматически генерируемые темы> |
| Теги | <это необязательно> |
2.2 Конфигурация маршрутизатора SPA
Discourse использует последнюю часть пути URL в качестве идентификатора для отдельной статьи блога.
Примеры:
https://mysite.com/blog/an-article-about-technology
https://mysite.com/blog/another-article-about-cats
Настройте ваш маршрутизатор SPA соответствующим образом, чтобы отдельные статьи блога соответствовали отдельным URL.
Также: Discourse предоставит ссылку обратно на отдельную статью блога, поэтому с точки зрения удобства использования (UX) хорошо, чтобы при клике на неё ваш сайт показывал actual статью.
2.3 Компонент статьи
Как уже говорилось, мы не можем использовать подход с <script></script> из [1]. Поэтому мы реализуем iframe и некоторые функции из javascripts/embed.js в нашем компоненте:
Article.vue
Вещи, которые вам следует отредактировать:
| элемент | описание |
|---|---|
| #YOUR-DISCOURSE-URL# | URL вашего экземпляра Discourse, например, discourse.mysite.com |
| #YOUR-SITE-URL# | URL вашего сайта, например, mysite.com, возможно также %2Fblog%2F, если путь к статьям блога не /blog/ |
<template>
<div id="article">
<!-- ваш отформатированный контент статьи здесь -->
<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, // слаг статьи блога, например, "an-article-about-technology", пока маршрут "https://mysite.com/blog/an-article-about-technology"
iframeHeight: 0 // Discourse сообщит нам точную высоту iframe (см.: метод receiveMessage)
}),
methods: {
// коммуникация через 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) {
// найти смещение iframe
const destY = this.findPosY(this.$refs["discourse-embed-frame"]) + event.data.top;
window.scrollTo(0, destY);
}
}
},
// Спасибо 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);
}
}
2.4 Конфигурация встраивания Discourse
Теперь, когда опрос RSS/Atom-каналов настроен и реализация на вашем сайте готова, мы наконец можем настроить встраивание на экземпляре Discourse.
Перейдите в Администрирование → Настройка → Встраивание и добавьте хост:
| Ключ | Значение |
|---|---|
| Разрешённые хосты | базовый URL вашего сайта, например, “mysite.com” |
| Имя класса | необязательное имя класса для стилизации |
| Список разрешённых путей | например, “/blog/.*” |
| Публиковать в категорию | та же категория, что и в настройках RSS Polling Category |
3. Заключительные замечания
Опрос RSS/Atom-каналов, а также сам Discourse создадут новую тему, если она не существует для отдельной статьи блога. Убедитесь, что опрос RSS/Atom-каналов выполняется первым (т.е. подождите, пока тема не будет создана, прежде чем посещать статью блога на вашем сайте).
Причина: Discourse не может парсить заголовок и краткое содержание, поэтому тема будет называться mysite.com с кратким содержанием Нам очень жаль, но этот сайт не работает без javascript. ![]()
Если по какой-то причине Discourse сработал первым, вы можете просто удалить тему и подождать, пока сработает опрос RSS/Atom-каналов.
всего доброго
– MK2k