여러 위치에 확장 공유하기
여러 위치에 확장 공유하기 (Sharing Extensions Across Multiple Locations)
일부 플러그인은 앱 전체의 여러 위치에서 재사용할 수 있는 확장성을 제공해야 할 수 있어요. 예를 들어 이 페이지에서 보여주는 패턴에서는 위젯을 기여해 여러 페이지에서 렌더링되도록 함으로써 플러그인을 확장 가능하게 만들 수 있어요. 이를 달성하려면 확장을 수집해 플러그인이나 앱 전체에서 사용할 수 있게 하는 Utility API를 사용하는 것이 권장 패턴이에요.
출처: 문서
본문
일부 플러그인은 앱 전체의 여러 위치에서 재사용할 수 있는 확장성을 제공해야 할 수 있어요. 예를 들어 이 페이지에서 보여주는 패턴에서는 위젯을 기여해 여러 페이지에서 렌더링되도록 함으로써 플러그인을 확장 가능하게 만들 수 있어요. 이를 달성하려면 확장을 수집해 플러그인이나 앱 전체에서 사용할 수 있게 하는 Utility API를 사용하는 것이 권장 패턴이에요.
개요 (Overview)
이 패턴은 Utility API와 확장 블루프린트를 결합해 다음을 수행해요.
-
확장 데이터 유형과 API 인터페이스 정의
-
확장을 만들기 위한 블루프린트 제공
-
확장을 입력으로 수집하는 Utility API 확장 만들기
-
API를 통해 확장 소비하기
이 접근 방식은 프론트엔드 시스템과의 기본 통합을 제공하며, 확장을 구성 가능하게 만들거나 추가 확장 지점을 갖는 것 같은 기능을 추가로 활용할 수 있게 해줘요.
기본 패턴 (Basic Pattern)
다음 예시는 여러 페이지에서 표시할 수 있는 위젯을 사용해 이 패턴을 보여줘요. 하지만 이 패턴은 유연하며 다음을 수행해야 하는 많은 다른 시나리오에 적용할 수 있어요.
-
같은 유형의 확장을 다른 페이지나 뷰 간에 공유
-
서드파티 플러그인이 분리된 방식으로 확장을 기여할 수 있도록 허용
-
여러 소스의 유사한 기능을 일관된 방식으로 집계
공유하는 기능 유형이 무엇이든 핵심 개념은 동일하게 유지돼요.
1. 확장 데이터 유형과 API 인터페이스 정의하기
먼저 플러그인의 -react 패키지(예: backstage-plugin-foo-react)에서 위젯 유형과 API 인터페이스를 정의해요.
in backstage-plugin-foo-react
import { createApiRef } from '@backstage/frontend-plugin-api';import { ComponentType } from 'react';export interface FooWidgetProps { title: string;}// Define what data each widget provides, prefer using lazy loading for large pieces of functionality like componentsexport interface FooWidget { title: string; size: 'small' | 'medium' | 'large'; loader: () => Promise<ComponentType<FooWidgetProps>>;}// Define the API interfaceexport interface FooWidgetsApi { getWidgets(): FooWidget[];}// Create the API referenceexport const fooWidgetsApiRef = createApiRef<FooWidgetsApi>({ id: 'plugin.foo.widgets',});
2. 확장을 만드는 블루프린트 제공하기
다음으로, 역시 -react 패키지(예: backstage-plugin-foo-react)에서 확장을 만드는 블루프린트를 만들어요. 블루프린트는 내부 데이터 참조를 만들고 dataRefs 속성을 통해 노출해요. 이 블루프린트는 다른 플러그인이 사용하도록 export될 거예요.
in backstage-plugin-foo-react
import { createExtensionBlueprint, createExtensionDataRef, ExtensionBoundary,} from '@backstage/frontend-plugin-api';const fooWidgetDataRef = createExtensionDataRef<FooWidget>().with({ id: 'foo.widget',});export const FooWidgetBlueprint = createExtensionBlueprint({ kind: 'foo-widget', // Attach extensions created with this blueprint to the API extension that will be created in the next step attachTo: { id: 'api:foo/widgets', input: 'widgets' }, output: [fooWidgetDataRef], *factory(params: FooWidget, { node }) { yield fooWidgetDataRef({ title: params.title, size: params.size, loader: ExtensionBoundary.lazyComponent(node, params.loader), }); }, dataRefs: { widget: fooWidgetDataRef, },});
3. 확장을 수집하는 Utility API 확장 만들기
기본 플러그인 패키지(예: backstage-plugin-foo)에서 위젯을 입력으로 수집하는 Utility API 확장을 만들어요. 이는 FooWidgetBlueprint.dataRefs.widget를 통해 블루프린트의 데이터 참조를 import한다는 점에 유의하세요.
in backstage-plugin-foo
import { ApiBlueprint, createExtensionInput,} from '@backstage/frontend-plugin-api';import { FooWidgetBlueprint, fooWidgetsApiRef,} from 'backstage-plugin-foo-react';export const FooWidgetsApiExtension = ApiBlueprint.makeWithOverrides({ name: 'widgets', inputs: { widgets: createExtensionInput([FooWidgetBlueprint.dataRefs.widget]), }, factory(originalFactory, { inputs }) { // Collect all widgets from the inputs and forward them to the API implementation const widgets = inputs.widgets.map(w => w.get(FooWidgetBlueprint.dataRefs.widget), ); return originalFactory(defineParams => defineParams({ api: fooWidgetsApiRef, deps: {}, factory: () => ({ getWidgets: () => widgets, }), }), ); },});
이제 다른 플러그인은 -react 패키지에서 블루프린트를 import하고 API가 수집할 위젯 확장을 만들 수 있어요.
in a consuming plugin
import { FooWidgetBlueprint } from 'backstage-plugin-foo-react';const barWidgetExtension = FooWidgetBlueprint.make({ name: 'bar', params: { title: 'Bar Widget', size: 'small', loader: () => import('./components/BarWidget').then(m => m.BarWidget), },});const bazWidgetExtension = FooWidgetBlueprint.make({ name: 'baz', params: { title: 'Baz Widget', size: 'medium', loader: () => import('./components/BazWidget').then(m => m.BazWidget), },});
4. API를 통해 확장 소비하기
이제 Utility API를 소비하는 사용 가능한 어떤 방법으로든 위젯을 소비할 수 있어요. 예를 들어 컴포넌트에서 위젯에 접근하는 방법은 다음과 같아요.
in backstage-plugin-foo
import { useApi } from '@backstage/frontend-plugin-api';import { fooWidgetsApiRef } from 'backstage-plugin-foo-react';import { Suspense, lazy } from 'react';export function FooPageContent() { const widgetsApi = useApi(fooWidgetsApiRef); const widgets = widgetsApi.getWidgets(); return; // load and render widgets ...}
Utility API 소비에 대한 자세한 내용은 Utility API 소비 페이지를 참고하세요.