discovery-list-container-top Outlet 위에 게시물을 렌더링

이 부분은 잘 못해서 죄송합니다.

ask discourse에 이렇게 질문을 했어요:

테마(theme)에서 두 개의 토픽의 첫 번째 게시물을 토픽 목록 위, discovery-list-container-top 아웃렛(Outlet)에 렌더링하고 싶은데 어떻게 해야 하나요?

여러 버전을 제시해 주었는데, 제 눈에는 작동할 것 같아 보였어요. 하지만 모두 미리보기에서 오류를 발생시켰습니다. 다시 ask discourse에 질문했어요:

샘플 코드를 파일 대신 JS 탭에 넣으려면 어떻게 해야 하나요?

그러자 이 버전을 주었습니다:

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

class FirstPosts extends Component {
  @tracked posts = [];

  constructor() {
    super(...arguments);
    this.loadPosts();
  }

  async loadPosts() {
    let topicIds = [123, 456]; // change to your topic IDs
    let posts = [];
    for (let id of topicIds) {
      let res = await fetch(`/t/${id}.json`);
      let data = await res.json();
      if (data.post_stream && data.post_stream.posts.length > 0) {
        posts.push(data.post_stream.posts[0]);
      }
    }
    this.posts = posts;
  }

  static template = <template>
    {{#each this.posts as |post|}}
      <div class="first-post-preview">
        <h4>{{post.topic_title}}</h4>
        {{{post.cooked}}}
      </div>
    {{/each}}
  </template>;
}

export default apiInitializer("0.11.1", api => {
  api.renderInOutlet("discovery-list-container-top", FirstPosts);
});

그리고 오류 코드를 ask discourse에 붙여넣자 이 버전을 주었습니다:

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

// Global data store (hacky, but works for the JS tab)
window.firstPostsData = [];

fetch("/t/123.json")
  .then(r => r.json())
  .then(data => window.firstPostsData.push(data.post_stream.posts[0]));

fetch("/t/456.json")
  .then(r => r.json())
  .then(data => window.firstPostsData.push(data.post_stream.posts[0]));

export default apiInitializer(api => {
  api.renderInOutlet("discovery-list-container-top", 
    <template>
      {{#each (theme-prefix "firstPostsData" window=true) as |post|}}
        <div class="first-post-preview">
          <h4>{{post.topic_title}}</h4>
          {{{post.cooked}}}
        </div>
      {{/each}}
    </template>
  );
});

제가 뭘 잘못하고 있는지 알려주실 수 있나요?

콘솔에 나타난 오류는 다음과 같았습니다:

Compile error: SyntaxError: /theme-4/discourse/api-initializers/theme-initializer.gjs:

미리보기에 표시된 내용은 이랬습니다:

감사합니다

조금 수정했는데 이렇게 하면 작동하는 것 같습니다:

import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { htmlSafe } from "@ember/template";
import { ajax } from "discourse/lib/ajax";
import { apiInitializer } from "discourse/lib/api";

class FirstPosts extends Component {
  @tracked posts = [];

  constructor() {
    super(...arguments);
    this.loadPosts();
  }

  async loadPosts() {
    let topicIds = [123, 1807]; // change to your topic IDs
    let posts = [];
    for (constid of topicIds) {
      const data = await ajax(`/t/${id}.json`);
      if (data.post_stream && data.post_stream.posts.length > 0) {
        posts.push(data.post_stream.posts[0]);
      }
    }
    this.posts = posts;
  }

  <template>
    {{#each this.posts as |post|}}
      <div class="first-post-preview">
        <h4>{{post.topic_title}}</h4>
        {{htmlSafe post.cooked}}
      </div>
    {{/each}}
  </template>;
}

export default apiInitializer((api) => {
  api.renderInOutlet("discovery-list-container-top", FirstPosts);
});

수정: 삼중 중괄호 대신 ajax()htmlSafe를 사용하도록 변경했습니다.

네이트, 감사합니다! 네이트가 무엇을 변경했는지 파악하려고 합니다.

네이트의 코드는 제 첫 번째 버전과 같은 것 같습니다.

for 루프에서 let을 const로 교체하셨네요.

맞는 건가요?

ask discourse 버전에서는 오류가 발생합니다.

for (let id of topicIds) {
      let res = await fetch(`/t/${id}.json`);
      let data = await res.json();
      if (data.post_stream && data.post_stream.posts.length > 0) {
        posts.push(data.post_stream.posts[0]);
      }
    }

네이트의 버전은 실행됩니다.

for (let id of topicIds) {
      const res = await fetch(`/t/${id}.json`);
      const data = await res.json();
      if (data.post_stream && data.post_stream.posts.length > 0) {
        posts.push(data.post_stream.posts[0]);
      }
    }

누군가 무엇이 문제인지 설명해 주실 수 있나요? 왜 let은 작동하지 않고 const는 작동하는 건가요?

다시 한번 감사합니다, 네이트.

let를 시도해 보았지만 결과는 동일했습니다. 보통 fetch()ajax()를 사용할 때는 const를 사용하거든요.

에ラー가 static template = 줄에서 발생한다고 생각합니다. 이 줄을 사용하면 다음과 같은 에러가 나요:

[THEME 10283 'Pokemon Theme'] Error: connector component has no associated template. Ensure the template is colocated or authored with gjs.
    at h (plugin-connectors.js:35:11)
    at eY.renderInOutlet (plugin-api.gjs:1116:5)
    at todo.gjs:43:7
    at eH (plugin-api.gjs:3363:10)
    at Object.initialize (api.js:21:14)
    at i.initialize (app.js:265:28)
    at index.js:379:19
    at e.each (index.js:183:7)
    at e.walk (index.js:112:10)
    at e.each (index.js:59:20)
    at e.topsort (index.js:65:10)
    at iL._runInitializer (index.js:392:11)
    at iL.runInstanceInitializers (index.js:377:10)
    at l._bootSync (instance.js:116:22)
    at iL.didBecomeReady (index.js:784:18)
    at invoke (index.js:262:14)
    at m.flush (index.js:180:11)
    at g.flush (index.js:334:19)
    at z._end (index.js:762:32)
    at _boundAutorunEnd (index.js:499:12)

그냥 <template>을 직접 사용하면 에러가 발생하지 않습니다. 여기서는 static template을 사용하는 것이 유효하지 않다고 생각하므로, 템플릿 태그를 직접 사용하는 것이 작동합니다.

바보처럼 테스트 중이던 버전을 삭제해 버렸고, 이제 Nate의 최신 버전을 실행할 수 없어요

theme-initializer.gjs:18 Uncaught (in promise) ReferenceError: constid is not defined
    at n.loadPosts (theme-initializer.gjs:18:10)
    at new n (theme-initializer.gjs:12:10)
    at h.createComponent (index.js:259:12)
    at $.create (index.js:419:28)
    at Object.evaluate (index.js:985:23)
    at Object.evaluate (index.js:103:106)
    at tr.evaluateSyscall (index.js:2873:20)
    at tr.evaluateInner (index.js:2852:64)
    at tr.evaluateOuter (index.js:2849:10)
    at tH.next (index.js:4167:45)
    at tH._execute (index.js:4157:21)
    at tH.execute (index.js:4133:41)
    at tq.sync (index.js:4194:120)
    at tz.render (index-BCp6wOJU.js:4636:43)
    at index-BCp6wOJU.js:4934:16
    at eX (index.js:2414:7)
    at tG._renderRoots (index-BCp6wOJU.js:4914:7)
    at tG._renderRootsTransaction (index-BCp6wOJU.js:4962:12)
    at tG._renderRoot (index-BCp6wOJU.js:4904:10)
    at tG._appendDefinition (index-BCp6wOJU.js:4828:10)
    at tG.appendOutletView (index-BCp6wOJU.js:4818:10)
    at invoke (index.js:264:14)
    at m.flush (index.js:180:11)
    at g.flush (index.js:334:19)
    at z._end (index.js:762:32)
    at _boundAutorunEnd (index.js:499:12)

이 가장 첫 번째 버전만이 실행할 수 있는 유일한 버전이에요

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

class FirstPosts extends Component {
  @tracked posts = [];

  constructor() {
    super(...arguments);
    this.loadPosts();
  }

  async loadPosts() {
    let topicIds = [98, 239]; // change to your topic IDs
    let posts = [];
    for (let id of topicIds) {
      const res = await fetch(`/t/${id}.json`);
      const data = await res.json();
      if (data.post_stream && data.post_stream.posts.length > 0) {
        posts.push(data.post_stream.posts[0]);
      }
    }
    this.posts = posts;
  }

  <template>
    {{#each this.posts as |post|}}
      <div class="first-post-preview">
        <h4>{{post.topic_title}}</h4>
        {{{post.cooked}}}
      </div>
    {{/each}}
  </template>;
}

export default apiInitializer((api) => {
  api.renderInOutlet("above-main-container", FirstPosts);
});

이 작업을 수행하기 위해 테마 JS 탭을 사용하려고 하고 있어요

아마도 GitHub 기반 테마로 전환해야 할까요? 제 한계가 바로 거기에 있는 걸까요?

네, 여기서는 letconst가 사실상 동일하므로 그것이 문제가 아닙니다.

(테마 컴포넌트와 플러그인의 경우) 해당 접미사가 인터프리터에 사전 컴파일을 지시하기 때문에, 그 문법으로 템플릿을 포함하는 것은 독립형 .gjs 파일에서만 가능하다고 생각합니다. 내장된 온라인 테마 시스템에 어떤 영향을 미치는지는 정확히 모르겠습니다.

어쨌든 GitHub로 이전하는 것은 매우 좋은 아이디어입니다.

좋은 조언 주셔서 감사합니다. 지금 그 작업을 시도하고 있습니다. 지금까지 이만큼 해낸 것이 저에게 큰 도움이 되었습니다. Nate의 위 코드는 실제로 작동하며 두 개의 토픽을 상단에 배치합니다. 제 테마 아이디어로 새 토픽을 시작하고, 배운 내용을 문서화해 보려고 합니다. ask.discourse.org는 정말 놀라운 곳입니다!