임베드된 사이트가 "토론 로딩 중"에서 멈춤

안녕하세요! NextJS 웹 앱에 Discourse를 임베드하려고 할 때 문제가 발생하고 있습니다. 동일한 오류를 다루는 기존 스레드에서 답변을 찾아보았지만, 제 문제를 해결할 방법을 찾지 못했습니다.

현재 사용 중인 임베드 코드는 다음과 같습니다:

<script id="discourse" type="text/javascript" data-nscript="afterInteractive">DiscourseEmbed = {
              discourseUrl: 'https://qanvast.discourse.group/',
              discourseEmbedUrl: 'https://web-uat.qanvast.com/sg/interior-design-singapore/forefront-interior-the-alcove-26226?image=769596',
              // className: 'CLASS_NAME',
            };

            (function() {
              var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
              d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
              (document.getElementsByTagName('head')[0] 
              || document.getElementsByTagName('body')[0]).appendChild(d);
            })();</script>

프론트엔드에서는 “Loading Discussions…” 상태로 멈춰 있습니다. 처음에는 CSP와 관련이 있다고 생각했지만, 해당 도메인을 이미 임베딩 허용 목록(Embedding Allowlist)에 추가해 두었습니다. 콘솔 로그나 네트워크 호출에서도 오류가 표시되지 않습니다.

몇 시간째 이 문제로 막혀 있어서 도움이 필요할 것 같습니다. 도움을 주시면 감사하겠습니다.

안녕하세요 @Edrian_C_Bertulfo, 환영합니다 :wave:

이 주제를 따라 해보셨나요? 이렇게 하면 되지만, NexJS 웹 앱에서 작동할지는 잘 모르겠어요…

릴리, 안녕하세요!

답변 주셔서 감사합니다. 해당 게시물의 안내에 따라 진행했는데도 여전히 "토론 로딩 중…"이라는 메시지가 무한히 반복되는 문제에 막혀 있습니다.

결국 어떻게 됐나요?

저도 Next.js를 사용할 때 동일한 문제를 겪고 있습니다. 첫 로드 시(주제가 생성되기 전에) ‘토론 로딩 중’ 상태에 멈춰 있습니다. 새로고침을 하면 댓글/토론 시작 부분이 표시되므로, 주제 자체는 정상적으로 생성되지만 로딩 상태가 업데이트되지 않습니다(댓글 입력框이 표시되려면 새로고침이 필요합니다).

페이지를 새로고침하지 않아도 주제가 생성되었음을 알릴 수 있는 콜백이나 유사한 기능이 있으면 좋겠습니다. iframe에서는 이것이 가능한지 모르겠습니다.

음, 실제로는 주제가 생성된 후에도 전혀 로드가 되지 않아요…
적어도 제 환경에서는요.

어떤 팁이 있을까요?

다음 앱에 있는 코드가 이렇습니다. 이전에 말씀드린 대로 동작하며, 새로고침을 눌러야 합니다. 잘 동작하는지 알려주세요.

가끔은 ‘토론 로딩 중’ 메시지가 지나기 위해 여러 번 새로고침을 하거나, 잠시 기다린 후 새로고침을 해야 합니다.

<DiscourseComments
          discourseUrl="https://discourseurl.com/"
          discourseEmbedUrl={embedUrl}
          username="system"
        />

컴포넌트:

"use client"

import { useEffect, useRef } from "react"

/**
 * 웹사이트에 Discourse 댓글을 임베드하기 위한 React 컴포넌트
 *
 * @param {Object} props - 컴포넌트 props
 * @param {string} props.discourseUrl - Discourse 인스턴스의 URL (끝에 슬래시 포함)
 * @param {string} [props.discourseEmbedUrl] - 현재 페이지의 URL (자동 토픽 생성용)
 * @param {number} [props.topicId] - 기존 Discourse 토픽의 ID (discourseEmbedUrl의 대안)
 * @param {string} [props.username] - 토픽 생성을 위한 사용자 이름
 * @param {string} [props.className] - 임베드에 추가할 CSS 클래스 이름
 * @param {string} [props.referrerPolicy] - iframe의 Referrer 정책
 */
export default function DiscourseComments({
  discourseUrl,
  discourseEmbedUrl,
  topicId,
  username,
  className,
  referrerPolicy = "no-referrer-when-downgrade",
}) {
  const initialized = useRef(false)

  useEffect(() => {
    // 중복 초기화 방지
    if (initialized.current) return
    initialized.current = true

    // 필수 props 검증
    if (!discourseUrl) {
      console.error("DiscourseComments: discourseUrl은 필수입니다")
      return
    }

    if (!discourseEmbedUrl && !topicId) {
      console.error("DiscourseComments: discourseEmbedUrl 또는 topicId 중 하나는 제공되어야 합니다")
      return
    }

    // Discourse 임베드 구성
    const config = {
      discourseUrl,
      discourseReferrerPolicy: referrerPolicy,
    }

    if (discourseEmbedUrl) {
      config.discourseEmbedUrl = discourseEmbedUrl
    }

    if (topicId) {
      config.topicId = topicId
    }

    if (className) {
      config.className = className
    }

    // 전역 DiscourseEmbed 객체 설정
    window.DiscourseEmbed = config

    // Discourse 임베드 스크립트 로드
    const script = document.createElement("script")
    script.type = "text/javascript"
    script.async = true
    script.src = `${discourseUrl}javascripts/embed.js`
    document.head.appendChild(script)

    // 정리
    return () => {
      document.head.removeChild(script)
      delete window.DiscourseEmbed
    }
  }, [discourseUrl, discourseEmbedUrl, topicId, className, referrerPolicy])

  return (
    <>
      <div id="discourse-comments"></div>
      {username && <meta name="discourse-username" content={username} />}
    </>
  )
}