Discourse는 단일 페이지 애플리케이션(SPA)입니다. 겪고 계신 문제는 사용 중인 스크립트가 이 점을 인지하지 못하기 때문에 발생합니다. Discourse에서 홈페이지나 다른 어떤 페이지를 방문하더라도 다음과 같은 구조를 받게 됩니다.
<html>
<head>
스크립트를 포함한 head 콘텐츠
</head>
<body>
<section id="main">
페이지 콘텐츠
</section>
</body>
</html>
다른 페이지로 이동할 때 새로고침되는 것은 다음 안의 콘텐츠뿐입니다.
<section id="main">
즉, DOM이 변경되었지만 사용자 정의 스크립트는 다시 실행되지 않습니다. 토픽 페이지를 직접 방문해보면 정상적으로 로드되는 것을 확인할 수 있습니다.
.
이제 Discourse에서 이 기능이 작동하도록 하는 방법을 알아봐야 합니다.
plugin-api에는 게시물을 "장식(decorate)"하는 데 사용할 수 있는 메서드가 있습니다.
https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L282-L318
이를 사용하여 게시물이 렌더링될 때 제3자 스크립트를 실행할 수 있습니다.
아래는 필요한 코드입니다. 이 코드를 테마의 common > header 탭에 추가하세요.
<script type="text/discourse-plugin" version="0.8">
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";
const loadScript = require("discourse/lib/load-script").default;
const { iconHTML } = require("discourse-common/lib/icon-library");
const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
class: "woxo-preview-icon"
});
const previewMarkup = () => {
const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;
return markup;
};
// create a post decorator
api.decorateCookedElement(
post => {
const woxoWidgets = post.querySelectorAll("div[data-mc-src]");
if (woxoWidgets.length) {
woxoWidgets.forEach(woxoWidget => {
if (post.classList.contains("d-editor-preview")) {
woxoWidget.innerHTML = previewMarkup();
return;
}
loadScript(WOXO_SCRIPT_SRC).then(() => {
const script = document.head.querySelector(
`script[src*="cdn2.woxo.tech"]`
);
script.dataset.usrc = "";
window.MC.Loader.init();
});
});
}
},
{ id: "render-woxo-widgets" }
);
</script>
그런 다음 CSP에 몇 개의 도메인을 추가해야 합니다. 다음을
content_security_policy_script_src
사이트 설정에 추가하세요.
https://*.woxo.tech/
https://us-central1-core-period-259421.cloudfunctions.net/availableComponentTracks
마지막으로, 정적 컴포저 미리보기용 CSS를 조금 추가해야 합니다.
이것은 테마의 common > CSS 탭에 들어갑니다.
.woxo-preview {
height: 400px;
width: 100%;
background: var(--primary-low);
display: flex;
align-items: center;
justify-content: center;
.woxo-preview-icon {
font-size: var(--font-up-4);
color: var(--primary-high);
}
}
그런 다음 어떤 게시물에든
<div data-mc-src="f4b43a8f-c188-4f80-8206-36d9f7529f13#instagram"></div>
을 추가하면 위젯이 렌더링되고 완전히 기능적으로 작동합니다.
JavaScript를 살펴보면 맨 위에 두 가지 옵션이 있다는 것을 알 수 있습니다.
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";
WOXO_SCRIPT_SRC를 woxo가 제공하는 src로 변경하세요. 만드는 모든 임베드에 대해 동일해야 합니다.
PREVIEW_ICON은 컴포저 미리보기에서 사용하려는 아이콘의 이름으로 변경하세요. 컴포저에서 이 코드를 실행하는 것은 비용이 다소 들기 때문에, 컴포저에는 다음과 같은 정적 미리보기가 표시됩니다.
선택한 아이콘이 중앙에 표시됩니다.
무엇이 일어나고 있는지 따라가 보고 싶다면 주석이 달린 코드 사본을 여기에 첨부합니다.
주석 달린 코드
<script type="text/discourse-plugin" version="0.8">
// 옵션
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";
// 스크립트가 올바르게 로드되도록 Discourse의 Load script 라이브러리를 사용합니다.
// 이미 로드된 경우 스크립트를 중복하지 않도록 충분히 지능적으로 작동합니다.
const loadScript = require("discourse/lib/load-script").default;
// 정적 컴포저 미리보기에서 사용하려는 아이콘의 svg를 가져오기 위해
// Discourse의 Icon HTML 함수를 로드합니다.
const { iconHTML } = require("discourse-common/lib/icon-library");
// 컴포저 미리보기 아이콘 설정
const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
class: "woxo-preview-icon"
});
// 컴포저 미리보기 마크업을 위한 헬퍼 함수 생성
const previewMarkup = () => {
const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;
return markup;
};
// 게시물 장식기(decorator) 생성
api.decorateCookedElement(
post => {
// 이 게시물에 woxo 위젯이 있는가?
const woxoWidgets = post.querySelectorAll("div[data-mc-src]");
// 네, 그렇다면 작업을 수행합니다.
if (woxoWidgets.length) {
// 각 woxo 위젯에 대해
woxoWidgets.forEach(woxoWidget => {
// 컴포저 위젯인 경우 정적 미리보기로 교체하고
// 조기에 종료합니다.
if (post.classList.contains("d-editor-preview")) {
woxoWidget.innerHTML = previewMarkup();
return;
}
// 컴포저가 아닌 경우 woxo 스크립트를 로드합니다.
loadScript(WOXO_SCRIPT_SRC).then(() => {
// woxo 스크립트는 매우 특이합니다. 스크립트 태그에
// 빈 data-usrc 속성이 없으면 작동하지 않습니다. 따라서 추가합니다.
const script = document.head.querySelector(
`script[src*="cdn2.woxo.tech"]`
);
script.dataset.usrc = "";
// 모든 준비가 끝났으니 woxo 스크립트의 init 메서드를 호출합니다.
window.MC.Loader.init();
});
});
}
},
// 메모리 누수를 방지하기 위해 장식기에 id를 추가합니다.
{ id: "render-woxo-widgets" }
);
</script>