레지스트리 엔트리
레지스트리 엔트리는 Wippy 백엔드가 프론트엔드 아티팩트 — 마이크로 프론트엔드 앱 또는 재사용 가능한 웹 컴포넌트 — 를 선언하여 Web Host가 이를 발견하고 서빙할 수 있게 하는 방법입니다. 이 문서는 모듈의 _index.yaml, 해당 package.json의 wippy 블록, 그리고 이 둘을 연결하는 wippy-meta.json 파일 사이의 계약을 설명합니다.
런타임에 이 엔트리들을 처리하는 wippy/views 모듈 설정은 Views를 참고하세요.
레지스트리 엔트리란
모든 프론트엔드 아티팩트는 모듈의 _index.yaml에서 registry.entry로 선언됩니다. kind: registry.entry 마커는 이 엔트리가 Lua 컴포넌트를 직접 정의하는 것이 아니라 다른 모듈이 소비하는 메타데이터를 담고 있음을 Wippy 레지스트리에 알립니다.
흔한 함정:
view.page와view.component는kind값이 아닙니다. 항상kind: registry.entry를 작성하고 프론트엔드 아티팩트 타입은meta.type에 넣으세요.kind: view.page와kind: view.component는 유효하지 않은 형태입니다.
최소한의 올바른 형태:
- name: main
kind: registry.entry
meta:
type: view.page
version: "1.0"
namespace: app.views
entries:
- name: main
kind: registry.entry
meta:
type: view.page
name: main
title: Admin Panel
icon: tabler:layout-dashboard
order: 0
announced: true
secure: false
url: /app
base_path: app/main
entry_point: app.html
mountRoute: /home/:part(.*)*
meta 블록이 wippy/views가 읽는 부분입니다. meta.type 필드는 지원되는 두 가지 아티팩트 종류를 구분합니다.
meta.type 판별자
| 값 | 의미 |
|---|---|
view.page |
마이크로 프론트엔드 앱(완전한 SPA)으로, Web Host 내부의 iframe에 렌더링됩니다 |
view.component |
페이지 어디에나 임베드할 수 있는 Web Component(커스텀 엘리먼트)입니다 |
meta의 다른 모든 필드는 이 타입의 맥락에서 해석됩니다. 한쪽 타입에만 적용되는 필드는 타입별 레퍼런스 페이지(view.page, view.component)에서 설명합니다.
specification 마커
레지스트리에 참여하는 모든 프론트엔드 패키지는 package.json 최상위에 "specification": "wippy-component-1.0"을 선언합니다. 이 문자열은 해당 패키지가 wippy-component 계약을 따른다는 것 — 알려진 형태의 wippy 블록을 가지며 @wippy-fe/vite-plugin으로 빌드되었다는 것 — 을 Wippy(및 툴링)에 알리는 핸드셰이크입니다.
{
"name": "@wippy/app-main",
"version": "1.0.0",
"specification": "wippy-component-1.0",
"wippy": { ... }
}
specification의 존재 자체가 런타임 동작을 바꾸지는 않지만, wippy/views는 레지스트리에서 로드한 엔트리를 검증할 때 이를 사용합니다.
wippy-meta.json 계약
@wippy-fe/vite-plugin은 빌드된 번들 옆에 wippy-meta.json 파일을 생성합니다. 이 파일은 아티팩트의 런타임 메타데이터 — props 스키마, events 스키마, title, icon, proxy 주입 설정 — 에 대한 정식 소스 오브 트루스입니다.
에이전트와 툴링을 위한 요약:
- 생성 주체:
view.page앱은wippyPagePlugin(),view.component웹 컴포넌트는wippyComponentPlugin(). - 작성 주체:
wippy-meta.json을 손으로 작성하는 사람은 없습니다. vite 플러그인이package.json에서 생성합니다. - 소비 주체:
wippy/views가 페이지/컴포넌트 디스크립터와 API 응답을 구성할 때 서빙된 번들 루트에서 이를 읽습니다. - YAML의 역할:
_index.yaml은 배포 정책과 명시적으로 오버라이드하는 모든 필드에 대해 권위를 유지합니다.
wippy/views가 registry.entry를 로드할 때, 아티팩트의 서빙된 번들 루트에서 wippy-meta.json을 읽습니다. 페이지의 경우 그 루트는 페이지의 url + base_path이며, 웹 컴포넌트의 경우 현재 엔트리들은 컴포넌트를 url에서 직접 서빙합니다. YAML이 항상 우선합니다: _index.yaml은 자신이 선언하는 모든 필드에 대해 우선권을 가집니다. wippy-meta.json은 특정 필드에 YAML 오버라이드가 없을 때 wippy/views가 읽는 기본값을 제공합니다. 배포 정책 필드 — announced, secure, url, mountRoute, base_path — 는 컴포넌트 작성이 아니라 운영자의 결정을 표현하므로 _index.yaml에 설정해야 합니다. 이들에 대한 package.json/wippy-meta.json 작성 표면은 존재하지 않습니다. (base_path는 페이지와 컴포넌트 모두에서 인정되며, 현재 app-template 컴포넌트 엔트리들은 단지 이를 생략할 뿐입니다.)
반면 entry_point는 FE에서 작성하면서 동시에 YAML로 오버라이드할 수 있습니다. 이는 패키지의 wippy 블록에서 wippy-meta.json으로 구워집니다 — 페이지는 wippy.path(@wippy-fe/vite-plugin이 필수로 요구하며, 생략하면 플러그인이 wippy.path is required for a page package를 던집니다), 컴포넌트는 wippy.tagName/browser입니다. _index.yaml의 meta.entry_point 필드는 그 작성된 기본값 위에 얹히는 배포별 선택적 오버라이드이며, YAML 전용 필드가 아닙니다.
이 분리 덕분에 컴포넌트 작성자는 표시 메타데이터를 package.json의 wippy 블록에 한 번만 작성하고, vite 플러그인이 빌드 시점에 이를 작성자 기본값으로 wippy-meta.json에 굽습니다. 컴포넌트를 배포하는 운영자는 라우팅과 접근 정책을 YAML에 설정하며, 표시 수준의 필드도 거기서 오버라이드할 수 있습니다.
공통 필드
다음 필드들은 view.page와 view.component 엔트리 모두의 meta 블록에 나타납니다.
| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
type |
string | — | view.page 또는 view.component (필수) |
name |
string | 엔트리 이름 | API 응답에서 사용되는 식별자 |
title |
string | — | 사람이 읽을 수 있는 표시 이름 |
icon |
string | — | Iconify 참조, 예: tabler:layout-dashboard |
announced |
boolean | — | 목록 API에서의 노출을 제어합니다. 의미는 타입별로 다릅니다(아래 참고) |
secure |
boolean | false |
접근에 인증이 필요합니다 |
url |
string | — | 정적 파일 서빙을 위한 기본 URL 접두사(CDN 오리진 또는 로컬 마운트 경로) |
entry_point |
string | index.html / index.js |
정적 디렉터리 내의 엔트리 파일 이름 |
타입별 announced 의미
announced 플래그는 meta.type에 따라 다른 결과를 가집니다:
-
view.page: 페이지가 내비게이션 사이드바(GET /api/public/pages/list)에 나타나는지를 제어합니다.announced: false로 설정하면 내비게이션에서 페이지가 숨겨지지만, 직접 접근하면 페이지는 여전히 로드됩니다. 임베드용 또는 보조 페이지에 적합한 정당한 패턴입니다. -
view.component:GET /api/public/components/list에 포함될지를 결정합니다.announced: false이면 컴포넌트는 해당 엔드포인트에서 완전히 제외되며, 이는 Web Host가 그 스크립트 태그를 결코 주입하지 않고customElements.get(tagName)이 undefined로 남는다는 뜻입니다. 자동 로드가 필요한 컴포넌트에는announced: true가 필수입니다 — 자세한 내용은 view.component를 참고하세요.
서빙 필드의 조합 방식
마이크로 프론트엔드 앱의 경우, 세 필드가 조합되어 Web Host가 로드하는 HTML URL을 만듭니다:
<url>/<base_path>/<entry_point>
예를 들어 url: /app, base_path: app/main, entry_point: app.html이면 호스트는 /app/app/main/app.html을 가져옵니다.
base_path와 entry_point의 분리는 의도적입니다. Web Host는 로드된 페이지에 <url>/<base_path>/를 HTML <base> 태그로 주입하며, 이는 브라우저가 그 페이지 내의 모든 상대 URL을 해석하는 방식을 결정합니다. 엔트리 파일은 베이스의 하위 디렉터리에 있어도 됩니다 — 중요한 것은 베이스가 모든 리소스에 상대 경로로 도달할 수 있는 공통 루트를 가리켜야 한다는 점입니다.
예를 들어 번들이 다음과 같은 레이아웃을 가진다면:
static/
shared/
vendor.js
app/
index.html ← entry_point: app/index.html
app.js
그리고 index.html이 ../shared/vendor.js를 참조한다면, base_path는 app/이 아니라 static/(즉 app/과 shared/를 모두 포함하는 디렉터리)를 가리켜야 합니다. base_path: app으로 설정하면 ../shared/vendor.js가 서빙 디렉터리 밖으로 해석되어 404가 됩니다.
모든 에셋이 엔트리 파일과 같은 위치에 있는 일반적인 경우에는 base_path와 entry_point가 있는 디렉터리가 같은 레벨이므로 이 구분이 드러나지 않습니다. 번들이 형제 디렉터리 간에 리소스를 공유할 때만 문제가 됩니다.
웹 컴포넌트의 경우에도 호스트는 서빙 URL을 같은 방식으로 구성합니다:
<url>/<base_path>/<entry_point>
현재 app-template 컴포넌트 엔트리들은 base_path를 생략하지만, 이는 지원되며 동일하게 조합됩니다(<url>/<base_path>/<entry_point>) — 따라서 그런 엔트리에서는 URL이 <url>/<entry_point>로 축약됩니다. 페이지와의 차이는 컴포넌트가 자체 HTML <base> 태그를 주입받는 대신 <script type="module">로 주입된다는 점입니다.