플러그인 마이그레이션하기
플러그인 마이그레이션하기 (Migrating Plugins)
이 가이드를 통해 프론트엔드 플러그인과 그 컴포넌트, 라우트, API를 새 프론트엔드 시스템으로 마이그레이션할 수 있어요.
출처: 문서
본문
이 가이드를 통해 프론트엔드 플러그인과 그 컴포넌트, 라우트, API를 새 프론트엔드 시스템으로 마이그레이션할 수 있어요.
주요 개념은 라우트, 컴포넌트, API가 이제 확장이라는 것이에요. 적절한 확장 블루프린트를 사용해 이 모두를 확장으로 마이그레이션할 수 있어요.
플러그인 마이그레이션하기
참고
자체 프로젝트에서만 사용되는 플러그인을 마이그레이션하는 경우가 아니라면, 모든 플러그인이 이전 시스템에 대한 지원을 유지할 것을 권장해요. 이 예시에서 추가된 코드는 플러그인의 새 src/alpha.tsx 진입점에 추가되어야 해요.
레거시 프론트엔드 시스템에서 플러그인은 자체 plugin.ts 파일에 다음과 같이 정의됐어요.
my-plugin/src/plugin.ts
import { createPlugin } from '@backstage/core-plugin-api'; export const myPlugin = createPlugin({ id: 'my-plugin', apis: [ ... ], routes: { ... }, externalRoutes: { ... }, });
플러그인의 실제 정의를 마이그레이션하려면 @backstage/frontend-plugin-api가 export하는 새 createFrontendPlugin 유틸리티로 플러그인을 다시 만들어야 해요. 새 createFrontendPlugin 함수는 API가 이제 확장이므로 더 이상 apis를 받지 않아요.
my-plugin/src/alpha.tsx
import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; export default createFrontendPlugin({ // The plugin ID is now provided as `pluginId` instead of `id` pluginId: 'my-plugin', // bind all the extensions to the plugin extensions: [/* APIs will go here, but don't worry about those yet */], routes: { ... }, externalRoutes: { ... }, });
위 코드는 모든 확장을 플러그인에 바인딩해요. 중요: 위 코드 스니펫이 제안하는 것처럼 플러그인을 패키지의 기본 export로 별도 진입점, 바람직하게는 /alpha로 내보내야 해요. src/alpha.tsx가 package.json에 export되어 있는지 확인하세요.
my-plugin/package.json
"exports": { ".": "./src/index.ts", "./alpha": "./src/alpha.tsx", "./package.json": "./package.json" }, "typesVersions": { "*": { "alpha": [ "src/alpha.tsx" ], "package.json": [ "package.json" ] } },
페이지 마이그레이션하기
이전에 createRoutableExtension 확장 함수로 만들던 페이지는 @backstage/frontend-plugin-api가 export하는 PageBlueprint 확장 블루프린트로 새 프론트엔드 시스템에 마이그레이션할 수 있어요.
새 시스템에서는 플러그인이 이전보다 더 많은 정보를 제공해요. 예를 들어 플러그인이 이제 앱 코드의 일부가 아니라 페이지 경로를 제공할 책임을 져요.
예를 들어 다음 페이지가 있다면:
export const FooPage = fooPlugin.provide( createRoutableExtension({ name: 'FooPage', component: () => import('./components').then(m => m.FooPage), mountPoint: rootRouteRef, }),);
그리고 플러그인 README에 다음 지침이 있다면:
<Route path="/foo" element={<FooPage />} />
.ts에서 .tsx로 바꿔야 할 수도 있다는 점을 염두에 두고, 다음과 같이 마이그레이션할 수 있어요.
import { PageBlueprint } from '@backstage/frontend-plugin-api';const fooPage = PageBlueprint.make({ params: { // This is the path that was previously defined in the app code. // It's labelled as the default one because it can be changed via configuration. path: '/foo', // You can reuse the existing routeRef. routeRef: rootRouteRef, // these inputs usually match the props required by the component. loader: () => import('./components/').then(m => <m.FooPage />), },});
그런 다음 fooPage 확장을 플러그인에 추가하세요.
my-plugin/src/alpha.tsx
import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; export default createFrontendPlugin({ pluginId: 'my-plugin', // bind all the extensions to the plugin extensions: [], extensions: [fooPage], ... });
컴포넌트 마이그레이션하기
createComponentExtension으로 만든 컴포넌트를 교체하는 동등한 유틸리티는 컴포넌트가 사용되는 문맥에 따라 달라지며, 보통 export의 명명 패턴으로 표시돼요. 대부분은 기존 블루프린트 중 하나로 마이그레이션할 수 있지만, 드물게 createExtension을 직접 사용해야 할 수도 있어요.
API 마이그레이션하기
Utility API에 관해 염두에 둬야 할 몇 가지 사항이 있어요.
React 패키지 인터페이스와 참조 변경
-react 패키지부터 시작해 보겠어요. TypeScript 인터페이스와 API ref를 export하는 행위는 이전 시스템에서 바뀌지 않았어요. 일반적으로 그대로 둘 수 있어요. 설명을 위해 인터페이스와 그 API ref의 예시는 다음과 같아요.
in @internal/plugin-example-react
import { createApiRef } from '@backstage/frontend-plugin-api';/** * Performs some work. * @public */export interface WorkApi { doWork(): Promise<void>;}/** * The work interface for the Example plugin. * @public */export const workApiRef = createApiRef<WorkApi>({ id: 'plugin.example.work',});
파일 상단에 이전 섹션에서 마이그레이션한 @backstage/frontend-plugin-api의 업데이트된 import를 이전 @backstage/core-plugin-api 대신 사용한다는 점에 유의하세요.
이제 API의 구현을 마이그레이션해 보겠어요. core-plugin-api import를 변경하기 전에 API는 다음과 유사했을 거예요.
in @internal/plugin-example, 참고 이것은 레거시 코드
import { storageApiRef, createApiFactory } from '@backstage/core-plugin-api';import { workApiRef } from '@internal/plugin-example-react';import { WorkImpl } from './WorkImpl';const exampleWorkApi = createApiFactory({ api: workApiRef, deps: { storageApi: storageApiRef }, factory: ({ storageApi }) => new WorkImpl({ storageApi }),});
우리가 만들 주요 변경 사항은
-
이 가이드의 상단 섹션에 따라 이전
@backstage/core-plugin-apiimport를 새@backstage/frontend-plugin-api패키지로 변경 -
기존 API factory를
ApiBlueprint로 감싸기
import를 단순화하고 정리한 최종 결과는 다음과 같을 수 있어요.
in @internal/plugin-example
import { storageApiRef, ApiBlueprint } from '@backstage/frontend-plugin-api';import { workApiRef } from '@internal/plugin-example-react';import { WorkImpl } from './WorkImpl';const exampleWorkApi = ApiBlueprint.make({ params: defineParams => defineParams({ api: workApiRef, deps: { storageApi: storageApiRef }, factory: ({ storageApi }) => new WorkImpl({ storageApi }), }),});
마지막으로 exampleWorkApi 확장을 플러그인에 추가해 보겠어요.
my-plugin/src/alpha.tsx
import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; export default createFrontendPlugin({ pluginId: 'my-plugin', // bind all the extensions to the plugin extensions: [fooPage], extensions: [exampleWorkApi, fooPage], ... });
추가 작업 (Further work)
Utility API가 이제 완전한 확장이므로, 이전에 어떻게 사용됐는지와 새 프론트엔드 시스템이 무엇을 제공하는지 더 크게 살펴볼 수 있어요. 예를 들어 현재 애플리케이션에 적합하다면 API에 구성 가능성이나 입력을 추가하는 것을 고려할 수 있어요.