템플릿 및 JS API를 위한 인라인 스크립트 태그 현대화

테마에서 <script type='text/discourse-plugin> 또는 <script type='text/x-handlebars'> 사용은 이제 비추천(deprecated)됩니다. 테마에서 이러한 태그를 사용하는 경우 아래 지침에 따라 업데이트해야 합니다.

일반적인 <script> 및 <script type='text/javascript'>는 이 변경 사항의 영향을 받지 않습니다.

타임라인

이는 대략적인 추정치이며 변경될 수 있습니다

  • 2025년 5월 - 콘솔 비추천 메시지 활성화

  • 2025년 7월 - 관리자 경고 배너 활성화

  • 2025년 9월 말 2026년 3월 - 기능 제거

<script type='text/x-handlebars'> 변환

이 방법을 통해 도입된 템플릿은 전용 .hbs 파일로 이동하거나 gjs 파일로 리팩토링해야 합니다.

HBS로 유지하려면, 커넥터 템플릿은 다음 위치에 배치할 수 있습니다:

{theme}/javascripts/discourse/connectors/{outlet-name}/{connector-name}.hbs

그리고 컴포넌트 템플릿은 다음 위치에 배치할 수 있습니다:

{theme}/javascripts/discourse/components/{component-name}.hbs

:warning: 2026년 3월 이후 .hbs 파일도 비추천 대상이 됩니다. 이 변환을 완료한 후에는 Deprecating .hbs file extension in themes and plugins 의 지침으로 진행하세요.

최신 .gjs 형식으로 커넥터와 컴포넌트를 빌드하려면 테마 개발자 튜토리얼의 해당 장을 참고하세요:

<script type='text/discourse-plugin'> 변환

이 태그 내부의 코드는 전용 JavaScript 파일로 마이그레이션할 수 있습니다.

관리자 패널 인터페이스를 통해 테마를 개발하는 경우, <script>에서 코드를 복사하여 JS 탭(// your code here이라고 표시된 곳)으로 이동하세요.

로컬에서 테마를 개발하는 경우, 다음 위치에 새 파일을 생성하세요.

{theme}/javascripts/discourse/api-initializers/init-theme.js

그리고 아래 래퍼를 추가하고 표시된 위치에 코드를 배치하세요:

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
  // Your code here
});

스크립트 태그에서 다른 JS 모듈을 가져오는 유일한 방법은 require() 구문을 사용하는 것이었습니다. .js 파일에서는 여전히 작동하지만 곧 비추천 대상이 되므로, 이제 현대적인 ES6 import로 변환하는 것이 좋습니다. 예를 들어:

- const I18n = require("discourse-i18n").default;
+ import I18n from "discourse-i18n";
- const { h } = require("virtual-dom");
+ import { h } from "virtual-dom";

JS 초기화자에 대한 자세한 정보는 다음을 참조하세요:

아마도 아주 멍청한 질문일 수도 있지만, 저는 아주 단순한 테마 컴포넌트를 하나 가지고 있는데, 이걸 관리자 콘솔의 <head> 바로 아래에 직접 넣고 있습니다:

<script type="text/x-handlebars" data-template-name="/connectors/top-notices/whos-online-below-site-header">
{{whos-online}}
</script>

제가 이 게시물을 제대로 이해하고 있다면, 플러그인 아웃렛에 단순히 내용을 추가하는 것조차도 이제 별도의 테마 컴포넌터 폴더를 만들고, 그걸 GitHub에 호스팅한 뒤, 컴포넌트를 추가해야 한다는 뜻인가요?

절대 그렇지 않기를 바랍니다. 그렇지 않으면 제 단순한 테마 컴포넌트 대부분이 깨져버릴 테니까요 :grimacing:

이제 JS 탭이 있으므로, 아마도 api.renderInOutlet을(를) 사용할 수 있을 것입니다.

아, 커넥터/컴포넌트로도 이것이 가능하다는 것을 보지 못했는데, 링크된 글에서 이 내용을 찾았습니다:

생각했던 것보다 더 쉬운 것 같네요, 감사합니다!

이 게시물 감사합니다!
아주 기초적인 질문일 수 있지만:
우리는 샌드박스가 없으므로, 진행하기 전에 확실하게 확인해야 합니다.
영향을 받는 테마를 업데이트해야 하는데, 아래에 나와 있는 것처럼 “head” 탭의 "Script"와 관련된 모든 코드를 JS 탭으로 이동시켜야 한다는 제 이해가 맞는지요:

거의 맞지만, 완전히는 아닙니다. 스크립트 태그를 제거하고, import를 다음과 같은 형태로 변경해야 합니다:

import { ajax } from "discourse/lib/ajax";

그런 다음, 이 모든 내용을 JS 탭에 붙여넣되, 아래 코드 내부에 넣어야 합니다:

저희 Discourse 사이트(Discourse에서 호스팅 중)에서 현재 다음과 같은 오류 바가 표시되고 있습니다(이것이 이 스레드로 오게 된 계기입니다):

저희가 ‘Light’ 테마에 대해 직접 커스터마이징을 한 적은 없는 것으로 알고 있으며, 관리 페이지를 살펴봐도 시스템에서 제공하는 기본값 이상으로 보이는 내용은 보이지 않습니다(하지만 무언가를 놓치고 있을 수도 있습니다).

저희와 같은 호스팅 사이트의 경우, 시간이 지나면 이 문제가 자연스럽게 해결될 가능성이 높나요, 아니면 저희 측에서 조치를 취해야 하나요?

감사합니다.
-Brad

이 문제를 해결하기 위해 조치를 취해야 합니다. 알아서 해결되지 않습니다.

Chrome 개발자 도구로 사이트를 간단히 확인해 보았더니, 관련 코드는 highlightjs에 ‘chapel’ 언어를 추가하는 것과 관련이 있는 것으로 보입니다.

‘Light’ 테마로 이동한 후 '코드 편집’을 누르면, HTML 탭 중 하나에서 이 코드를 찾을 수 있어야 합니다. 그런 다음 이 주제의 원문(OP)에 있는 지침을 따라 코드를 ‘JS’ 탭으로 이동시킬 수 있습니다.

감사합니다, @david! Chapel 하이라이팅을 위해 커스터마이징을 했다는 사실을 잊고 있었어요. 에러 배너만 보고는 혼자서는 그 해결책에 도달하기 어려웠을 것 같아, 도움과 조언에 진심으로 감사드립니다.

-Brad

간단한 .html 파일이 있습니다:

<script type='text/x-handlebars' data-template-name='/connectors/below-site-header/oprs-top-container'>
    <div id='WW_T_D_1' class='oprs-top-leaderboard'></div>
</script>

마이그레이션을 수행하는 다양한 방법에 대해 다소 혼란스럽습니다. 누군가가 어떻게 해야 하는지 설명해 주시면 감사하겠습니다. 감사합니다.

단순히 renderInOutlet을 커넥터에 적용하면 됩니다

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
  api.renderInOutlet("below-site-header", <template>
    <div id='WW_T_D_1' class='oprs-top-leaderboard'></div>
  </template>);
});

감사합니다. 시도해 보았지만 작동하지 않았습니다 :confused:

내 구조와 코드는 다음과 같습니다.

below-site-header.js


export function test() {
    let test2 = document.querySelector('.test');
    console.log('test ', test2);
}

그리고 below-siteheader-connectors.hbs

<div class="test"></div>

이 분야에 초보이므로 도움이 많이 필요합니다. 이 저장소는 이전 개발자로부터 넘겨받은 것입니다.

안녕하세요, GitHub 저장소 링크를 공유해 주시겠어요? 감사합니다!

그래서 저는 제가 만든 작은 “make-avatar-bigger” 스크립트를 JS 탭(Desktop - <head> 밖)에 붙여넣었는데, 이 정도는 충분히 잘 동작합니다. 하지만 데스크톱에서만 적용되도록 하는 좀 더 간편한 방법이 있을까요? 모바일에서도 아바타가 커져서 전체적으로 좀 우스꽝스러워 보입니다.

참고용 코드는 다음과 같습니다:

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
 api.changeWidgetSetting('post-avatar', 'size', '70');
});

음… CSS로 이 부분을 조정해 볼까요?

아니면, 이렇게 해도 될 것 같습니다:

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
  const site = api.container.lookup("service:site");
  if (!site.mobileView) {
    api.changeWidgetSetting('post-avatar', 'size', '70');
  }
});

생각난 대로 바로 쓴 거예요.

완벽하게 해결되었습니다. 감사합니다!

친근한 알림입니다: post-avatar의 changeWidgetSetting은 비추천(deprecated)된 API이며 곧 제거될 예정입니다.

아래와 같이 코드를 수정하는 것이 좋습니다.

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer((api) => {
  const site = api.container.lookup("service:site");
  if (!site.mobileView) {
    api.modifyClass("component:post/avatar", (SuperClass) => class extends SuperClass {
      get size() { return "70"; } 
    });
  }
});

이것에 대해 official 테마 컴포넌트도 있는 것 같습니다? Avatar Size and Shape

이 특정 사용 사례에 맞을지는 확실하지 않지만, 그렇게 되어야 할 것 같습니다 (추가로, 업데이트가 필요할 경우 누군가가 고쳐 줄 것이라는 장점도 있습니다 :slight_smile:)

모두의 도움 덕분에 quick 'n dirty 방식에서 공식적으로 지원되는 방식으로 완전히 업그레이드했습니다!

레거시 컴포넌트(Desktop/Mobile을 별도로 처리하는 방식)를 사용하는 분들을 위해 참고드립니다. JS 탭은 Common 섹션에서만 사용 가능합니다. 다른 분들의 검색 시간을 조금이라도 줄일 수 있길 바랍니다 :slight_smile: