본문 바로가기
WIKI 기술 지식 베이스

플러그인 마이그레이션하기

원문 보기 위키 갱신

플러그인 마이그레이션하기 (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-api import를 새 @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에 구성 가능성이나 입력을 추가하는 것을 고려할 수 있어요.

더 알아보기 (Learn more)