From bd5757a9340e4cb6572fdb1fe4fe8f5ea977f4cf Mon Sep 17 00:00:00 2001 From: Christoph Jerolimov Date: Thu, 17 Sep 2026 15:04:29 +0200 Subject: [PATCH] refactor(homepage): narrow main entry point public API Move plugin implementation to plugin.ts and limit the package entry point to the default plugin export and translations module. Remove deprecated aliases and other named exports from the main entry point. Serve the demo homepage at /homepage and redirect / there. Signed-off-by: Christoph Jerolimov Co-authored-by: Cursor --- .../.changeset/narrow-homepage-public-api.md | 5 + workspaces/homepage/app-config.yaml | 14 ++- workspaces/homepage/packages/app/src/App.tsx | 34 ++--- .../homepage/plugins/homepage/dev/index.tsx | 13 +- .../homepage/plugins/homepage/report.api.md | 10 -- .../homepage/plugins/homepage/src/index.ts | 117 +----------------- .../{nfsExports.test.ts => plugin.test.ts} | 7 +- .../homepage/plugins/homepage/src/plugin.ts | 115 +++++++++++++++++ 8 files changed, 161 insertions(+), 154 deletions(-) create mode 100644 workspaces/homepage/.changeset/narrow-homepage-public-api.md rename workspaces/homepage/plugins/homepage/src/{nfsExports.test.ts => plugin.test.ts} (97%) create mode 100644 workspaces/homepage/plugins/homepage/src/plugin.ts diff --git a/workspaces/homepage/.changeset/narrow-homepage-public-api.md b/workspaces/homepage/.changeset/narrow-homepage-public-api.md new file mode 100644 index 00000000000..a4d38ac8461 --- /dev/null +++ b/workspaces/homepage/.changeset/narrow-homepage-public-api.md @@ -0,0 +1,5 @@ +--- +'@red-hat-developer-hub/backstage-plugin-homepage': minor +--- + +Narrow the main package entry point to the default plugin export and translations module. Move plugin implementation to `plugin.ts` and remove deprecated public API aliases. Serve the demo homepage at `/homepage` and redirect `/` there. diff --git a/workspaces/homepage/app-config.yaml b/workspaces/homepage/app-config.yaml index e12cc8bd732..8f6f3a1422e 100644 --- a/workspaces/homepage/app-config.yaml +++ b/workspaces/homepage/app-config.yaml @@ -1,25 +1,31 @@ app: title: Homepage Backstage App baseUrl: http://localhost:3000 + packages: all + extensions: - api:app/app-language: config: availableLanguages: ['en', 'de', 'fr', 'it', 'es', 'ja'] defaultLanguage: 'en' - # Disable the nav items that we're manually rendering in packages/app/src/modules/nav/Sidebar.tsx + - api:home/visits: true + - app-root-element:home/visit-listener: true + # Community home page (optional). Disable when using page:homepage alone. - page:home: config: - path: /home + path: /home # Default, just to make it more explicit title: Home + # Homepage-owned page (configurable path). Disable with page:homepage: false. - page:homepage: config: - path: / - title: Dynamic Homepage + path: /homepage # Default is / but to make it more explicit here + title: Homepage + - home-page-layout:homepage/dynamic-homepage-layout: config: customizable: true # false for read-only homepage layout diff --git a/workspaces/homepage/packages/app/src/App.tsx b/workspaces/homepage/packages/app/src/App.tsx index b157ac61506..f04998c1ff6 100644 --- a/workspaces/homepage/packages/app/src/App.tsx +++ b/workspaces/homepage/packages/app/src/App.tsx @@ -15,22 +15,28 @@ */ import { createApp } from '@backstage/frontend-defaults'; +import { + createFrontendModule, + PageBlueprint, +} from '@backstage/frontend-plugin-api'; +import { Navigate } from 'react-router-dom'; import { navModule } from './modules/nav'; import { signInModule } from './modules/signIn'; -import { - homepagePlugin, - homepageHomeModule, - homepageTranslationsModule, -} from '@red-hat-developer-hub/backstage-plugin-homepage'; -import rhdhThemeModule from '@red-hat-developer-hub/backstage-plugin-theme'; -export default createApp({ - features: [ - rhdhThemeModule, - navModule, - signInModule, - homepagePlugin, - homepageHomeModule, - homepageTranslationsModule, +const homeRedirectModule = createFrontendModule({ + pluginId: 'app', + extensions: [ + PageBlueprint.make({ + name: 'home-redirect', + params: { + path: '/', + noHeader: true, + loader: async () => , + }, + }), ], }); + +export default createApp({ + features: [navModule, signInModule, homeRedirectModule], +}); diff --git a/workspaces/homepage/plugins/homepage/dev/index.tsx b/workspaces/homepage/plugins/homepage/dev/index.tsx index 4358d64ec54..5f13f225942 100644 --- a/workspaces/homepage/plugins/homepage/dev/index.tsx +++ b/workspaces/homepage/plugins/homepage/dev/index.tsx @@ -46,11 +46,12 @@ import { starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; import homePlugin from '@backstage/plugin-home/alpha'; -import { - homepagePlugin, - homepageHomeModule, - homepageTranslationsModule, -} from '@red-hat-developer-hub/backstage-plugin-homepage'; +import homepagePlugin from '@red-hat-developer-hub/backstage-plugin-homepage/'; +// import { +// homepageHomeModule, +// } from '@red-hat-developer-hub/backstage-plugin-homepage'; +import homepageTranslationsModule from '@red-hat-developer-hub/backstage-plugin-homepage/homepage-translations-module'; + import rhdhThemeModule from '@red-hat-developer-hub/backstage-plugin-theme'; import { quickAccessApiRef } from '../src/api'; import { visitsApiRef } from '@backstage/plugin-home'; @@ -157,7 +158,7 @@ const app = createApp({ searchPlugin, homePlugin, homepagePlugin, - homepageHomeModule, + // homepageHomeModule, homepageTranslationsModule, homepageApiMocksModule, catalogDevModule, diff --git a/workspaces/homepage/plugins/homepage/report.api.md b/workspaces/homepage/plugins/homepage/report.api.md index 795f4eb0b87..d5057507c0f 100644 --- a/workspaces/homepage/plugins/homepage/report.api.md +++ b/workspaces/homepage/plugins/homepage/report.api.md @@ -23,11 +23,6 @@ import { RouteRef } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/frontend-plugin-api'; import { TranslationResource } from '@backstage/frontend-plugin-api'; -// @public -const homepageHomeModule: FrontendModule; -export { homepageHomeModule as homePageModule }; -export { homepageHomeModule }; - // @public const homepagePlugin: OverridableFrontendPlugin< { @@ -304,11 +299,6 @@ const homepagePlugin: OverridableFrontendPlugin< } >; export default homepagePlugin; -export { homepagePlugin as homePagePlugin }; -export { homepagePlugin }; - -// @public -export const homepageRouteRef: RouteRef; // @public export const homepageTranslationRef: TranslationRef< diff --git a/workspaces/homepage/plugins/homepage/src/index.ts b/workspaces/homepage/plugins/homepage/src/index.ts index 3b057af934f..e6d22d49195 100644 --- a/workspaces/homepage/plugins/homepage/src/index.ts +++ b/workspaces/homepage/plugins/homepage/src/index.ts @@ -28,121 +28,8 @@ ClassNameGenerator.configure(componentName => { : `v5-${componentName}`; }); -import { TranslationBlueprint } from '@backstage/plugin-app-react'; -import { - createFrontendModule, - createFrontendPlugin, -} from '@backstage/frontend-plugin-api'; -import { - catalogStarredWidget, - communityHomeWidgets, - disableRandomJoke, - disableToolkit, - entitySectionWidget, - featuredDocsCardWidget, - onboardingSectionWidget, - overrideHomeCatalogStarredWidget, - quickAccessCardWidget, - RecentlyVisitedWidget, - searchBarWidget, - templateSectionWidget, - TopVisitedWidget, -} from './extensions/homePageCards'; -import { homepageTranslations } from './translations'; -import { homePageLayoutExtension } from './extensions/homePageLayoutExtension'; -import { homepagePage } from './extensions/homepagePage'; -import { defaultWidgetsApi, quickAccessApi } from './extensions/apis'; -import { homepageRouteRef } from './homepageRouteRef'; +export { homepagePlugin as default } from './plugin'; -export { homepageRouteRef } from './homepageRouteRef'; - -/** - * Extensions owned by the homepage plugin. - * - * Widgets/layout attach to `page:homepage`. Persona filtering via - * homepage-backend is applied only by that layout. - */ -const homepageExtensions = [ - homepagePage, - homePageLayoutExtension, - onboardingSectionWidget, - entitySectionWidget, - templateSectionWidget, - defaultWidgetsApi, - quickAccessApi, - quickAccessCardWidget, - featuredDocsCardWidget, - searchBarWidget, - TopVisitedWidget, - RecentlyVisitedWidget, - catalogStarredWidget, -]; - -/** - * Homepage frontend plugin (`pluginId: homepage`). - * - * @public - */ -export const homepagePlugin = createFrontendPlugin({ - pluginId: 'homepage', - extensions: homepageExtensions, - routes: { - root: homepageRouteRef, - }, -}); - -/** - * Optional module for when community `@backstage/plugin-home` is also installed. - * - * Mirrors RH widgets onto `page:home` (no RH layout / no homepage-backend - * filtering) and disables community toolkit / joke demos and overrides the starred widget. - * - * @public - */ -export const homepageHomeModule = createFrontendModule({ - pluginId: 'home', - extensions: [ - ...communityHomeWidgets, - overrideHomeCatalogStarredWidget, - disableToolkit, - disableRandomJoke, - ], -}); - -/** - * @public - * @deprecated Use {@link homepageHomeModule}. - */ -export { homepageHomeModule as homePageModule }; - -/** - * @public - * @deprecated Use {@link homepagePlugin}. - */ -export { homepagePlugin as homePagePlugin }; - -/** - * Translation module for the Dynamic Home Page plugin. - * - * @public - */ -export const homepageTranslationsModule = createFrontendModule({ - pluginId: 'app', - extensions: [ - TranslationBlueprint.make({ - name: 'homepage-translations', - params: { - resource: homepageTranslations, - }, - }), - ], -}); +export { homepageTranslationsModule } from './plugin'; export { homepageTranslationRef, homepageTranslations } from './translations'; - -/** - * Default export required for Module Federation to emit the NFS expose. - * - * @public - */ -export default homepagePlugin; diff --git a/workspaces/homepage/plugins/homepage/src/nfsExports.test.ts b/workspaces/homepage/plugins/homepage/src/plugin.test.ts similarity index 97% rename from workspaces/homepage/plugins/homepage/src/nfsExports.test.ts rename to workspaces/homepage/plugins/homepage/src/plugin.test.ts index c9646b88ee3..92af21f555c 100644 --- a/workspaces/homepage/plugins/homepage/src/nfsExports.test.ts +++ b/workspaces/homepage/plugins/homepage/src/plugin.test.ts @@ -20,9 +20,7 @@ import { homepageHomeModule, homepagePlugin, homepageTranslationsModule, - homePageModule, - homePagePlugin, -} from '.'; +} from './plugin'; import { homepageTranslationRef, homepageTranslations } from './translations'; import { homePageLayoutExtension } from './extensions/homePageLayoutExtension'; import { HOMEPAGE_PAGE_ID } from './extensions/homepageAttach'; @@ -40,6 +38,7 @@ import { RecentlyVisitedWidget, TopVisitedWidget, } from './extensions/homePageCards'; + import { quickAccessApi, defaultWidgetsApi } from './extensions/apis'; type ExtensionAttach = { id: string; input: string }; @@ -75,7 +74,6 @@ describe('Dynamic Home Page plugin (NFS)', () => { expect(homepagePlugin.$$type).toBe('@backstage/FrontendPlugin'); expect(homepagePlugin.id).toBe('homepage'); expect(homepagePlugin.id).not.toBe(homePlugin.id); - expect(homePagePlugin).toBe(homepagePlugin); expect(homepagePlugin.getExtension(HOMEPAGE_PAGE_ID)).toBeDefined(); expect( homepagePlugin.getExtension( @@ -98,7 +96,6 @@ describe('Dynamic Home Page plugin (NFS)', () => { expect(homepageHomeModule).toBeDefined(); expect(homepageHomeModule.$$type).toBe('@backstage/FrontendModule'); expect(homepageHomeModule.pluginId).toBe('home'); - expect(homePageModule).toBe(homepageHomeModule); expect(communityHomeWidgets).toHaveLength(9); const extensions = getRuntimeExtensions(homepageHomeModule); diff --git a/workspaces/homepage/plugins/homepage/src/plugin.ts b/workspaces/homepage/plugins/homepage/src/plugin.ts new file mode 100644 index 00000000000..56de4596d5b --- /dev/null +++ b/workspaces/homepage/plugins/homepage/src/plugin.ts @@ -0,0 +1,115 @@ +/* + * Copyright Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TranslationBlueprint } from '@backstage/plugin-app-react'; +import { + createFrontendModule, + createFrontendPlugin, +} from '@backstage/frontend-plugin-api'; +import { + catalogStarredWidget, + communityHomeWidgets, + disableRandomJoke, + disableToolkit, + entitySectionWidget, + featuredDocsCardWidget, + onboardingSectionWidget, + overrideHomeCatalogStarredWidget, + quickAccessCardWidget, + RecentlyVisitedWidget, + searchBarWidget, + templateSectionWidget, + TopVisitedWidget, +} from './extensions/homePageCards'; +import { homepageTranslations } from './translations'; +import { homePageLayoutExtension } from './extensions/homePageLayoutExtension'; +import { homepagePage } from './extensions/homepagePage'; +import { defaultWidgetsApi, quickAccessApi } from './extensions/apis'; +import { homepageRouteRef } from './homepageRouteRef'; + +export { homepageRouteRef } from './homepageRouteRef'; + +/** + * Extensions owned by the homepage plugin. + * + * Widgets/layout attach to `page:homepage`. Persona filtering via + * homepage-backend is applied only by that layout. + */ +const homepageExtensions = [ + homepagePage, + homePageLayoutExtension, + onboardingSectionWidget, + entitySectionWidget, + templateSectionWidget, + defaultWidgetsApi, + quickAccessApi, + quickAccessCardWidget, + featuredDocsCardWidget, + searchBarWidget, + TopVisitedWidget, + RecentlyVisitedWidget, + catalogStarredWidget, +]; + +/** + * Homepage frontend plugin (`pluginId: homepage`). + * + * @public + */ +export const homepagePlugin = createFrontendPlugin({ + pluginId: 'homepage', + extensions: homepageExtensions, + routes: { + root: homepageRouteRef, + }, +}); + +/** + * Optional module for when community `@backstage/plugin-home` is also installed. + * + * Mirrors RH widgets onto `page:home` (no RH layout / no homepage-backend + * filtering) and disables community toolkit / joke demos and overrides the starred widget. + * + * @public + */ +export const homepageHomeModule = createFrontendModule({ + pluginId: 'home', + extensions: [ + ...communityHomeWidgets, + overrideHomeCatalogStarredWidget, + disableToolkit, + disableRandomJoke, + ], +}); + +/** + * Translation module for the Dynamic Home Page plugin. + * + * @public + */ +export const homepageTranslationsModule = createFrontendModule({ + pluginId: 'app', + extensions: [ + TranslationBlueprint.make({ + name: 'homepage-translations', + params: { + resource: homepageTranslations, + }, + }), + ], +}); + +export { homepageTranslationRef, homepageTranslations } from './translations';