원하는 아웃렛에 템플릿을 넣을 수 없습니다

javascripts/discourse/initializers/persistent-banner.gjs 파일에서 특정 플러그인 아웃렛에 템플릿을 삽입하려고 합니다.
코드:

import Component from "@glimmer/component";
import { apiInitializer } from "discourse/lib/api";

banner_plugin_outlet = settings.banner_position

export default apiInitializer("1.14.0", (api) => {
  try {
    banner_plugin_outlet = settings.banner_position
    api.renderInOutlet(
      banner_plugin_outlet,
      class persistentbanner extends Component {
        get bannerIsFilled() {
          if (settings.banner_text_content == "") {
            return false;
          } else if (settings.banner_visible == "hide") {
            return false;
          } else {
            return true;
          }
        }
        <template>
          {{#if this.bannerIsFilled}}
            <div class='persistent-banner'>
              <p>
                {{html_safe (theme-setting 'banner_text_content')}}
              </p>
            </div>
          {{/if}}
        </template>
      } 
    );
  } catch (e) {
    console.log(e);
  }
}

하지만 <template> 태그 안의 HTML이 아웃렛 위치에 표시되지 않습니다. 실제로는 어디에도 표시되지 않습니다. 어디서 잘못되고 있을까요?
리포지토리 링크: GitHub - NateDhaliwal/discourse-persistent-banner: A theme component for Discourse that cannot be closed by the user. · GitHub

초기화자를 사용하지 마세요. connectors 폴더를 사용하세요. 예제가 많이 있습니다.

그 이유는 선택할 수 있는 다양한 아웃렛이 있기 때문입니다.
이 코드는 Notification Banner 저장소에서 가져와서 수정했습니다.

아, 알겠습니다. 네, 말이 되네요. 혹시 기능적인 의도인지는 확신이 없어서요. 코드를 더 자세히 읽어야 했는데 죄송합니다.

다시 시작할 수 있도록 몇 가지 팁을 드릴게요:

  • 이 파일의 apiInitializer 호출 끝부분에 닫는 괄호가 하나 빠져 있습니다. 이대로는 동작하지 않습니다.

해당 문제를 수정하면 더 많은 오류가 보입니다.

  • banner_plugin_outlet이 선언되지 않았습니다. 여기에는 const가 필요합니다.

    두 번 할당하고 있네요? 두 번은 필요 없을 것 같습니다 :slight_smile:

    banner_plugin_outlet = settings.banner_position
    
    export default apiInitializer("1.14.0", (api) => {
      try {
        banner_plugin_outlet = settings.banner_position
    
  • 임포트(import)가 누락되어 있습니다:

    import { htmlSafe } from "@ember/template";
    import themeSetting from "discourse/helpers/theme-setting";
    
  • … 하지만 여기에서 themeSetting을 헬퍼로 사용하려고 해도 동작하지 않았습니다. 오류는 뜨지 않고 단순히 화면이 비어 보였기 때문에, 대신 아래 코드를 사용해 보세요:

            get bannerTextContent() {
              return settings.banner_text_content;
            }
            <template>
              {{#if this.bannerIsFilled}}
                <div class='persistent-banner'>
                  <p>
                    {{htmlSafe this.bannerTextContent}}
    
  • 항상 콘솔에서 오류를 확인하세요.

htmlSafe를 가져왔고, 정말 잘 작동했습니다!
정말 감사합니다!

네, 헬퍼는 gjs에서 작동하지 않습니다(그리고 필요도 없죠). getter를 정의하는 것은 괜찮습니다. 하지만 그렇게 하고 싶지 않다면 템플릿에서 settings "글로벌"에 직접 참조할 수 있습니다:

<template>
  {{htmlSafe settings.banner_text_content}}
</template>

고마워요. 그게 별로 투명하지 않아 보이던데요! :sweat_smile:

네, 그건 맞는 말이에요. 에러 메시지를 개선해 보겠습니다:


감사합니다. 개발자 경험에 정말 큰 도움이 됩니다.

알다시피, 위젯에 비해 .gjs를 사용하면서 개발자 경험이 극적으로 개선되었습니다.

하지만

gjs 컴포넌트를 사용할 때 매우 기이한 에러가 많이 발생하며, 이로 인해 문제를 찾기 쉽지 않습니다.

예를 들어, 헬퍼 이름을 잘못 입력해 보겠습니다:
{{html_safe this.bannerTextContent}}

그러면 다음과 같은 전형적인 에러가 발생합니다:

program.js:100 Uncaught (in promise) TypeError: Invalid value used as weak map key at WeakMap.set (<anonymous>)

(이름이 유효하더라도 import를 잊으면 여기에서도 같은 문제가 발생합니다)

뭐라고요?! :sweat_smile: 이런 사례가 정말 많습니다.

이것이 프레임워크를 사용하는 단점이라고 봐야 하나요?

아, 꽤 심각한 문제네요!

로컬에서 테스트해 보니 다음과 같은 내용이 표시됩니다:

WeakMap 오류를 어디서 확인하셨나요? 프로덕션 사이트에서 보셨다면… 아마도 성능 향상을 위해 프로덕션 빌드에서 최적화되어 제거되는 체크 중 하나일 수 있습니다.

가능하시다면 테마/플러그인을 개발할 때 반드시 적절한 개발 환경을 사용하시는 것을 권장합니다. 이 경우처럼 개발 환경에서는 더 나은 경험을 제공하는 경우가 많기 때문입니다.

네, 프로덕션 사이트에서 Theme CLI (를 사용하고 있는데, 이는 다른 면에서는 훌륭한 워크플로우이지만 아마도 단점 중 하나인 것 같습니다?

완전히 이해가 됩니다.

네, 플러그인이라면 제 1순위 선택지이지만, TC(테마 컴포넌트)의 경우 피드백의 즉각성 때문에(항상 유용하진 않지만!) 프로덕션 사이트에서 개발하려는 유혹이 큽니다.

하지만 방금 깨달은 것은, CLI로 로컬호스트를 입력하면 작동한다는 것입니다.

그러니까 그거였군요!

image

앞으로 그렇게 사용하겠습니다! :rocket:

왜 그게 불가능하다고 생각했는지 저도 모르겠습니다 :blush: :sweat_smile:

항상 도움 주셔서 감사합니다. 덕분에 (앞으로) 많은 시간을 절약할 수 있을 것 같습니다 :slight_smile:

맞아요! 테마 CLI를 사용하는 로컬호스트 환경에서 작업하는 방식을 선호하며, 다른 사람들에게도 추천합니다. 이러한 권장 워크플로를 문서화하는 부분에서는 확실히 더 나아질 수 있을 거예요 :eyes:

또 다른 팁은 discourse.theme-creator.io가 개발 모드 Ember 에셋으로 실행된다는 점입니다. 따라서 더 자세한 오류 메시지도 확인할 수 있을 거예요.