(비권장) 테마 또는 플러그인에서 Discourse 템플릿 오버라이드

이상적으로는 Discourse를 테마/플러그인으로 커스텀할 때 CSS, JavaScript 플러그인 API, 또는 플러그인 아웃렛을 사용해야 합니다. 이 중 어느 것도 사용 사례에 맞지 않는다면, Discourse 코어에 PR을 열거나 Meta의 Development 토픽에서 대화를 시작해 주세요. 커스텀을 더 쉽게 만들기 위해 새로운 아웃렛/API를 추가하는 것에 대해 항상 논의하는 것을 환영합니다.

모든 다른 옵션을 다 시도해 보았음에도 불구하고 템플릿 오버라이드가 필요한 경우가 있습니다. 이 기법은 테마/플러그인에서 어떤 Ember 컴포넌트나 라우트의 전체 템플릿을 오버라이드할 수 있게 해줍니다.

:rotating_light: 이것은 Discourse를 커스텀하는 권장되지 않는 방법입니다. Discourse 코어의 일상적인 변경 사항은 결국 템플릿 오버라이드와 충돌할 것이며, 포럼 렌더링 시 치명적인 오류를 일으킬 수 있습니다.

이 접근 방식을 결정했다면, 회귀를 감지하기 위한 충분한 자동화 테스트와 QA 프로세스를 갖추고 있는지 확인하세요. 템플릿 오버라이드가 포함된 테마/플러그인을 배포하는 경우, 포럼 관리자가 해당 테마/플러그인이 내포하는 안정성 위험을 인지하고 있는지 반드시 확인해야 합니다.

:rotating_light: :rotating_light: :rotating_light: 2023년 10월 업데이트: 새로운 기능에 대해 Discourse는 점점 더 Ember의 .gjs 파일 형식으로 작성된 컴포넌트 사용으로 이동하고 있습니다. 이러한 컴포넌트의 템플릿은 인라인으로 정의되며, 테마/플러그인에 의해 오버라이드될 수 없습니다.

앞으로 모든 템플릿 커스텀은 플러그인 아웃렛을 사용하여 수행해야 합니다.

가까운 미래에 이것이 깨질 것이라는 것을 알고 있지만, 그래도 문서를 보여주세요

컴포넌트 템플릿 오버라이드

Ember 컴포넌트 템플릿(즉, Discourse 코어의 components/* 아래에 있는 모든 것)를 오버라이드하려면, 테마/플러그인에서 동일한 이름을 가진 .hbs 파일을 생성해야 합니다. 예를 들어, Discourse 코어의 badge-button 컴포넌트 템플릿을 오버라이드하려면, 테마/플러그인의 다음 위치에 템플릿 파일을 생성해야 합니다:

:art: {theme}/javascripts/discourse/templates/components/badge-button.hbs

:electric_plug: {plugin}/assets/javascripts/discourse/templates/components/badge-button.hbs

오버라이드는 항상 /templates 디렉터리 안에 중첩되어야 하며, 코어 컴포넌트가 ‘동반(colocated)’ 템플릿을 가지고 있더라도 마찬가지입니다.

라우트 템플릿 오버라이드

라우트 템플릿 오버라이드(즉, templates/* 아래에 있는 모든 비-컴포넌트 템플릿)는 컴포넌트와 동일한 방식으로 작동합니다. 테마/플러그인에서 동일한 이름을 가진 템플릿을 생성합니다. 예를 들어, 코어의 discovery.hbs를 오버라이드하려면 다음과 같은 파일을 생성해야 합니다.

:art: {theme}/javascripts/discourse/templates/discovery.hbs

:electric_plug: {plugin}/assets/javascripts/discourse/templates/discovery.hbs

여러 테마/플러그인 간의 상호작용

여러 설치된 테마/플러그인이 동일한 템플릿을 오버라이드하는 경우, '승자’는 다음 목록에서 가장 낮은 순위 번호를 가진 것입니다:

  1. 테마 오버라이드 (가장 높은 테마 'id’가 승리)
  2. 플러그인 오버라이드 (가장 최신 알파벳 순 플러그인 이름이 승리)
  3. 코어

이 우선 순위는 또한 테마에서 플러그인 템플릿을 오버라이드할 수 있음을 의미합니다. 기술적으로는 다른 테마에서 테마 템플릿을, 다른 플러그인에서 플러그인 템플릿을 오버라이드할 수도 있지만, 플러그인 이름과 테마 id에 대한 의존성 때문에 동작이 의도치 않을 수 있습니다.

이것이 어떻게 작동하나요?

Discourse는 DiscourseTemplateMap 클래스에서 템플릿을 조립하고 우선순위를 부여합니다. 동반(colocated) 컴포넌트 템플릿의 경우, 해당 정보는 앱 초기화 동안 코어 템플릿 연관성을 대체하는 데 사용됩니다. 모든 다른 템플릿의 경우, 이 맵은 런타임의 리졸버에 의해 올바른 템플릿을 가져오는 데 사용됩니다.


이 문서는 버전 관리됩니다 - github에서 변경 사항을 제안하세요.

17개의 좋아요

그렇다면 모바일 템플릿은 어떻게 되나요? 코어에서 템플릿을 재작성하기 위한 디렉터리 구조는 무엇인가요?

완전히 동일하게 작동해야 합니다 - 코어 템플릿의 이름을 일치시키면 됩니다. 따라서 템플릿에 /mobile이 포함되어 있다면, 오버라이드에도 이를 포함하세요.

모바일 login.hbs 템플릿을 다시 작성해 보았는데 작동하지 않습니다. Imgur: The magic of the Internet 경로를 올바르게 설정한 것인가요?

제가 볼 때 스크린샷에는 전체 경로가 보이지 않습니다. 텍스트로 여기에 붙여넣어 주시겠습니까?

themeroot/javascripts/mobile/modal/login.hbs

경로에서 discourse/templates를 찾을 수 없습니다.

따라서 귀하의 경우, {theme}/javascripts/discourse/templates/mobile/modal/login.hbs가 됩니다.

2개의 좋아요

여전히 이런 상황인가요?

많은 코드를 오버라이드할 수 있는 기능이 제거되는 것이 다소 아쉬워집니다.

bespoke 위젯 시스템을 대체하는 것은 어느 정도 타당성이 있지만, 위젯 시스템은 기존 코드에 여러 수준에서 접근할 수 있는 능력을 제공했습니다. 이는 작은 블록을 지능적으로 표적하여 다음과 같은 방식으로 작업할 수 있게 해주어, 상당한 호환성 문제 위험을 줄여주었습니다:

  • 기능 추가
  • 다른 부분에 영향을 주지 않음.

예를 들어, 저는 Discourse Journal에서 위젯의 세밀한 오버라이드에 기반한 두 가지 주요 기능을 제거해야 했습니다. Glimmer에서 이를 재현하려면 템플릿 오버라이드 쌍(.gjs 파일 변경 시도 포함)을 사용해야 하는데, 이는 더 이상 지원되지 않는다고 합니다.

설령 이 기능이 지원되더라도, 위젯 프레임워크보다 더 큰 범위의 코드를 오버라이드해야 하며, 이는 코어 변경 사항이 오버라이드와 충돌할 위험이 증가하는 결과를 초래합니다.

이것은 플랫폼의 확장성 측면에서 건강한 상태가 아닙니다.

이 문제에 대해 어떤 조치가 취해질 수 있을까요?

7개의 좋아요

그 말씀에 공감합니다 - 위젯 확장성 API에는 좋은 점들이 있었습니다.

하지만 그 반대편에서는, 사람들이 어떤 임의의 메서드/장식을 도입하고 있을지 알 수 없기 때문에 코어에서 위젯 기반 UI의 어떤 부분도 수정하는 것이 incredibly 어려웠습니다. 그래서 위젯 커스터마이징이 상대적으로 안정적으로 보였다는 것입니다 - 코어 구현을 건드리기 두려웠기 때문입니다.

앞으로 이 문제에 대한 우리의 솔루션은 Wrapper Plugin Outlets입니다. 이를 통해 테마와 플러그인은 템플릿의 매우 작은 부분을 자신의 구현으로 선택적으로 오버라이드할 수 있습니다.

예를 들어, Chat이 어떻게 조건부로 홈 로고를 오버라이드하는지, 그리고 커스텀 컴포넌트로 대체하는지 확인해 보세요. 이는 기존 위젯 기반 헤더와 새로운 글리머(glimmer) 기반 헤더(곧 출시 예정! :tm:) 모두에서 작동합니다.

다양한 위치에 새로운 wrapper outlet을 추가하는 PR을 일반적으로 기꺼이 받아들이고 있습니다. 특정 사용 사례에 대해 확신이 서지 않는다면, 세부 사항과 함께 Development 토픽을 여는 것을 주저하지 마세요!

10개의 좋아요

좋아요, 그건 좋은 방향인 것 같네요. 감사합니다.

그 의미를 충분히 숙고하고, 그에 맞춰 전략을 조정해야 할 것 같습니다.

답변 주셔서 감사합니다!

6개의 좋아요