테마 컴포넌트에서 플러그인 JavaScript 오버라이드하기

Splitting up theme Javascript into multiple files에서 이어지는 토론입니다:

얼마 전 테마와 플러그인 중 어디에서 개발해야 하는지에 대한 논의가 있었습니다. https://www.pfaffmanager.com/ 의 Rails 부분은 이제 꽤 안정화되고 있으며, 저는 Rails 부분의 개발을 테마 컴포넌트로 옮기는 것을 추진하고 싶습니다. 현재까지는 잘 작동하고 있으며, 테마 컴포넌트의 템플릿과 초기화 프로그램(initializers)의 변경 사항이 예상대로 플러그인을 오버라이드하고 있습니다. 그러나, 테마의 javascripts/discourse/components/server-item.js.es6에 대한 변경 사항은 플러그인 내의 동일한 파일을 오버라이드하지 못하고 있습니다.

플러그인에서 Ember 관련 코드를 완전히 제거하고 테마에만 존재하도록 하는 방법도 생각해 볼 수 있지만, 그 모든 조각들을 옮기고 테스트한 뒤 서버에 배포하는 데 하루가 걸릴 것 같습니다. 제가 뻔한 것을 놓치고 있는 건가요? 테마 컴포넌트에 넣고 싶은 부분을 플러그인에서 완전히 제거해야 하는 건가요? 아니면 그냥 전부 플러그인에 두는 게 좋을까요?

테마 컴포넌트와 플러그인 양쪽에 동일한 코드가 있는 것은 조금 이상하게 느껴집니다. 제 생각에는 테마 컴포넌트/플러그인 중 하나를 선택한 뒤, 그쪽으로 완전히 집중하는 것이 더 좋겠습니다. 전체 파일을 오버라이드하는 것은 우리가 직접 하지 않는 방식이며, 권장하지도 않습니다. 코어/플러그인 동작을 오버라이드하려면, 테마 컴포넌트에서 api.modifyClass와 같은 메서드를 사용해야 합니다.

여기서 근본 원인은 플러그인 ES6 모듈이 코어/테마 모듈과 다른 방식으로 접두사가 붙기 때문이라고 추측합니다. 해당 사이트를 실행해 보니 모듈에 plugin 접두사가 붙어 있는 것을 확인할 수 있습니다. 테마 컴포넌트를 활성화하면 다른 엔트리가 보일 것 같지만, 접두사는 다를 것으로 예상됩니다.

Screenshot 2022-01-04 at 10.53.36

글쎄요, 저한테는 에임버(Ember) 전체가 여전히 이상해 보입니다. :man_shrugging:

좋아요. 모든 자바스크립트가 포함된 단일 플러그인으로 가겠습니다.

그리고 그 Object.keys 마법은 정말 멋지고, 저는 절대 알아낼 수 없었을 것 같습니다. 그 점에 대해 충분히 감사하다고 표현할 수 없습니다. 그리고 당신은 맞습니다:

(4) ['discourse/plugins/Pfaffmanager/discourse/components/compact-server-item', 
'discourse/plugins/Pfaffmanager/discourse/components/server-item', 
'discourse/theme-11/components/server-item', 
'discourse/theme-11/components/compact-server-item']

전반적으로 동의하지만, 몇 가지 예외적인 경우가 있습니다:

  1. 자바스크립트 변경 사항이 백엔드 변경 사항보다 압도적으로 많은 경우입니다. 이 경우 테마 컴포넌트는 코드를 빠르고 빠르게 배포하고 테스트 배포하는 데 훌륭한 방법입니다.

  2. 대부분의 기능이 기본 테마 컴포넌트로 제공될 수 있지만, 보완 플러그인을 추가하면 자바스크립트만으로는 불가능한 추가 기능을 더할 수 있는 경우입니다. 저는 '토픽 목록 미리보기(Topic List Previews)'에서 이 기법을 사용합니다. 컴포넌트가 애드온이 할 수 있는 것의 90%를 처리하지만, 플러그인도 함께 추가하면 몇 가지 추가적인 멋진 기능을 얻을 수 있습니다.

그럼에도 불구하고, 모든 것을 플러그인으로 패키징하는 것이 설정 및 설치에 대한 혼란을 줄이고 모든 것이 항상 동기화되도록 유지한다는 점에서 합리적입니다.

하지만 플러그인+테마 시나리오에서도, 플러그인과 테마 양쪽에 Ember 코드를 중복해서 넣지는 않겠습니다. 따라서 템플릿, 초기화 프로그램, 컴포넌트 중 대부분을 플러그인에서 제거하고, 테마에만 두어야 합니다.

설정 관련해서 혼란을 겪는 사람은 저뿐이므로, 큰 문제는 아닙니다. 테마의 베타 버전으로 전환하여 라이브 사이트에서 새로운 프론트엔드 기능을 테스트해 볼 수 있다는 아이디어를 정말 좋아합니다.

서버 측 코드는 플러그인에, 클라이언트 측 코드는 테마에 배치하는 방식은 매우 합리적입니다. 우리도 그렇게 하고 있습니다. :+1:

제가 반대했던 것은 같은 JavaScript 파일을 테마와 플러그인에 동시에 정의하는 것이었습니다.

네, 다들 같은 페이지에 있네요 :+1:t2:

이 문제를 도와주셔서 정말 감사드립니다.

제가 확인한 또 다른 문제는 qunit 테스트를 실행하는 것입니다. (테스트를 추가하는 방법을 어떻게든 알아낼 수 있다고 가정하겠습니다. 이는 완전히 별개의 문제이지만, 제 문제는 표시할 데이터로 테스트를 시드하는 방법을 모른다는 것입니다…). 플러그인에 qunit 테스트가 있다면, GitHub에 push할 때 테스트가 실행될 것 같습니다. (깨진 테스트가 실패하는 것을 꽤 확실하게 본 적이 있기 때문입니다.)

테마 컴포넌트도 같은 방식으로 작동하게 할 수 있을까요?

기술적으로는 가능할 수 있지만, 아직 테마를 위한 완성된 GitHub Actions 워크플로가 없는 것 같습니다. 현재 테마 테스트가 좀 더 개편되고 있습니다(ember-cli 전환을 위한 작업)가, 그 후에는 https://github.com/discourse/.github에 테마 테스트 워크플로 템플릿을 추가할 수 있을지도 모릅니다.

템플릿에 대해서도 이것이 사실인가요?

시나리오: 플러그인에 배포된 템플릿을 오버라이드하고 싶습니다. 하지만 코드로 제어되는 방식으로 오버라이드하기를 원합니다.

그래서 새 템플릿을 테마 컴포넌트에 포함시켜 보았습니다. 동일한 파일이 플러그인에도 존재하지만(내용은 다릅니다) 내용이 다릅니다.

이것은 제 개발 클라우드 설치 환경에서는 작동하지만, 표준 프로덕션 설치 환경에서는 작동하지 않습니다.

그러면 템플릿의 경우에도 이것이 성공할지 예측할 수 없다고 말하는 것이 타당할까요? 즉, 자산 파이프라인의 특성상 사전에 정의되거나 예측 가능한 우선순위가 없어 어떤 '템플릿’이 적용될지 예측할 수 없다는 뜻인가요?

저는 다음과 같은 위계 구조가 있다는 다소 이상한 가정으로 작업해 왔습니다.

  • 코어
  • 플러그인
  • 테마 컴포넌트
  • 로컬 사이트 변경 사항

위 위계 구조의 후속 레벨에 동일한 경로와 이름을 가진 "파일"을 배치하면 이전 레벨의 모든 "정의"를 오버라이드한다는 것이었습니다.

하지만 제 가정이 안전하지 않을 수도 있나요?

따라서 로컬 사이트 변경 사항을 제외하고 유일한 "패키지화"된 솔루션은 플러그인을 포크하여 그 안에서 직접 변경 사항을 적용하는 것인가요?

이는 어떤 의미에서는 아쉬운 일입니다. 커스터마이징에 대한 유지보수 노력이 증가하기 때문입니다. 주기적으로 메인 플러그인 저장소의 변경 사항을 병합해야 하니까요…

가장 좋은 방법은 기존 플러그인을 업데이트하여 테마 구성 요소가 사용할 수 있는 플러그인 아웃렛(outlet) 및/또는 커스터마이징 API를 제공하는 것입니다.

위에서 제가 언급한 내용은 특정 파일 전체 JS 파일(즉, es6 모듈)을 오버라이드하는 것에 관한 것이었습니다. 이것은 불가능합니다. 에셋 파이프라인은 플러그인/테마 모듈에 자동으로 플러그인/테마 이름 또는 ID를 접두사로 붙이기 때문에 코어와 충돌이 발생하는 것은 불가능합니다.

템플릿의 경우, 사람들이(일부 상황에서는 우리도 포함하여) 템플릿을 오버라이드하는 것을 알고 있으므로, 해당 시스템이 작동하도록 유지할 가능성이 높습니다. 하지만 이것이 **해킹(hack)**이라는 점을 기억해 주세요. 원래 구성 요소/컨트롤러의 동작이 변경되면, 오버라이드한 템플릿으로 인해 사이트가 깨질 가능성이 높습니다.

일반적으로 언급하신 계층 구조(코어, 플러그인, 테마)가 사실이어야 한다고 생각합니다. 따라서 다른 것을 보고 계시다면, 플러그인과 테마의 파일 경로에 대한 세부 정보를 공유해 주시기 바랍니다.

확인해 주셔서 감사합니다. 제 문제는 실제로는 별개의 문제였는데, 설명 덕분에 올바른 방향을 찾을 수 있었습니다! :blush: