From 8669210f3b4bd48c6473dfec464e807f56f0c730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 8 Aug 2024 16:15:57 +0200 Subject: [PATCH 1/4] added the frontend-extension-bundle role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Co-authored-by: Camila Belo Co-authored-by: blam Signed-off-by: Fredrik Adelöw --- .changeset/cold-tomatoes-vanish.md | 7 ++++++ docs/tooling/cli/02-build-system.md | 25 ++++++++++--------- packages/cli-node/api-report.md | 1 + packages/cli-node/src/roles/PackageRoles.ts | 5 ++++ packages/cli-node/src/roles/types.ts | 1 + packages/cli/config/eslint-factory.js | 1 + packages/cli/config/jest.js | 1 + packages/cli/src/commands/repo/fix.ts | 3 +++ packages/cli/src/commands/start/command.ts | 1 + .../cli/src/lib/bundler/packageDetection.ts | 8 +++--- .../rules/no-undeclared-imports.js | 1 + ...list-no-top-level-material-ui-4-imports.js | 6 ++++- scripts/verify-local-dependencies.js | 15 +++++++++-- 13 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 .changeset/cold-tomatoes-vanish.md diff --git a/.changeset/cold-tomatoes-vanish.md b/.changeset/cold-tomatoes-vanish.md new file mode 100644 index 0000000000..a6b34504c7 --- /dev/null +++ b/.changeset/cold-tomatoes-vanish.md @@ -0,0 +1,7 @@ +--- +'@backstage/cli-node': patch +'@backstage/cli': patch +'@backstage/eslint-plugin': patch +--- + +Added support for the `frontend-extension-bundle` role, which is used in conjunction with the new frontend system to ship extensions to your apps. diff --git a/docs/tooling/cli/02-build-system.md b/docs/tooling/cli/02-build-system.md index 1bcf7ad30c..1c850c7048 100644 --- a/docs/tooling/cli/02-build-system.md +++ b/docs/tooling/cli/02-build-system.md @@ -93,18 +93,19 @@ defined in the `package.json` of each package like this: These are the available roles that are currently supported by the Backstage build system: -| Role | Description | Example | -| ---------------------- | -------------------------------------------- | -------------------------------------------- | -| frontend | Bundled frontend application | `packages/app` | -| backend | Bundled backend application | `packages/backend` | -| cli | Package used as a command-line interface | `@backstage/cli`, `@backstage/codemods` | -| web-library | Web library for use by other packages | `@backstage/plugin-catalog-react` | -| node-library | Node.js library for use by other packages | `@backstage/plugin-techdocs-node` | -| common-library | Isomorphic library for use by other packages | `@backstage/plugin-permission-common` | -| frontend-plugin | Backstage frontend plugin | `@backstage/plugin-scaffolder` | -| frontend-plugin-module | Backstage frontend plugin module | `@backstage/plugin-analytics-module-ga` | -| backend-plugin | Backstage backend plugin | `@backstage/plugin-auth-backend` | -| backend-plugin-module | Backstage backend plugin module | `@backstage/plugin-search-backend-module-pg` | +| Role | Description | Example | +| ------------------------- | -------------------------------------------- | -------------------------------------------- | +| frontend | Bundled frontend application | `packages/app` | +| backend | Bundled backend application | `packages/backend` | +| cli | Package used as a command-line interface | `@backstage/cli`, `@backstage/codemods` | +| web-library | Web library for use by other packages | `@backstage/plugin-catalog-react` | +| node-library | Node.js library for use by other packages | `@backstage/plugin-techdocs-node` | +| common-library | Isomorphic library for use by other packages | `@backstage/plugin-permission-common` | +| frontend-plugin | Backstage frontend plugin | `@backstage/plugin-scaffolder` | +| frontend-extension-bundle | Extensions for the Backstage frontend | Typically only appears in adopter repos | +| frontend-plugin-module | Backstage frontend plugin module | `@backstage/plugin-analytics-module-ga` | +| backend-plugin | Backstage backend plugin | `@backstage/plugin-auth-backend` | +| backend-plugin-module | Backstage backend plugin module | `@backstage/plugin-search-backend-module-pg` | Most of the steps that we cover below have an accompanying command that is intended to be used as a package script. The commands are all available under the `backstage-cli package` category, and many of the commands will behave differently depending on the role of the package. The commands are intended to be used like this: diff --git a/packages/cli-node/api-report.md b/packages/cli-node/api-report.md index 9f7e525048..c07ab1ffcb 100644 --- a/packages/cli-node/api-report.md +++ b/packages/cli-node/api-report.md @@ -154,6 +154,7 @@ export type PackageRole = | 'node-library' | 'common-library' | 'frontend-plugin' + | 'frontend-extension-bundle' | 'frontend-plugin-module' | 'backend-plugin' | 'backend-plugin-module'; diff --git a/packages/cli-node/src/roles/PackageRoles.ts b/packages/cli-node/src/roles/PackageRoles.ts index 70b62e2479..ebed918193 100644 --- a/packages/cli-node/src/roles/PackageRoles.ts +++ b/packages/cli-node/src/roles/PackageRoles.ts @@ -53,6 +53,11 @@ const packageRoleInfos: PackageRoleInfo[] = [ platform: 'web', output: ['types', 'esm'], }, + { + role: 'frontend-extension-bundle', + platform: 'web', + output: ['types', 'esm'], + }, { role: 'frontend-plugin-module', platform: 'web', diff --git a/packages/cli-node/src/roles/types.ts b/packages/cli-node/src/roles/types.ts index d6eff04541..fd20a59231 100644 --- a/packages/cli-node/src/roles/types.ts +++ b/packages/cli-node/src/roles/types.ts @@ -27,6 +27,7 @@ export type PackageRole = | 'node-library' | 'common-library' | 'frontend-plugin' + | 'frontend-extension-bundle' | 'frontend-plugin-module' | 'backend-plugin' | 'backend-plugin-module'; diff --git a/packages/cli/config/eslint-factory.js b/packages/cli/config/eslint-factory.js index 96d8478ec0..b6d55aa0be 100644 --- a/packages/cli/config/eslint-factory.js +++ b/packages/cli/config/eslint-factory.js @@ -200,6 +200,7 @@ function createConfigForRole(dir, role, extraConfig = {}) { case 'web-library': case 'frontend': case 'frontend-plugin': + case 'frontend-extension-bundle': case 'frontend-plugin-module': case 'frontend-dynamic-container': return createConfig(dir, { diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index bef7b76f96..1153781af5 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -54,6 +54,7 @@ function getRoleConfig(role) { case 'web-library': case 'common-library': case 'frontend-plugin': + case 'frontend-extension-bundle': case 'frontend-plugin-module': return { testEnvironment: require.resolve('jest-environment-jsdom') }; case 'cli': diff --git a/packages/cli/src/commands/repo/fix.ts b/packages/cli/src/commands/repo/fix.ts index a55440c53f..c117d9b436 100644 --- a/packages/cli/src/commands/repo/fix.ts +++ b/packages/cli/src/commands/repo/fix.ts @@ -246,6 +246,8 @@ function guessPluginId(role: PackageRole, pkgName: string): string | undefined { case 'frontend': case 'frontend-plugin': return pkgName.match(/plugin-(.*)/)?.[1]; + case 'frontend-extension-bundle': + return undefined; case 'frontend-plugin-module': return pkgName.match(/plugin-(.*)-module-/)?.[1]; case 'backend-plugin': @@ -364,6 +366,7 @@ export function fixPluginPackages( role === 'common-library' || role === 'web-library' || role === 'node-library' || + role === 'frontend-extension-bundle' || role === 'frontend-plugin-module' // TODO(Rugvip): Remove this once frontend modules are required to have a plugin ID ) { return; diff --git a/packages/cli/src/commands/start/command.ts b/packages/cli/src/commands/start/command.ts index aa46b717bb..3e419f99cf 100644 --- a/packages/cli/src/commands/start/command.ts +++ b/packages/cli/src/commands/start/command.ts @@ -46,6 +46,7 @@ export async function command(opts: OptionValues): Promise { }); case 'web-library': case 'frontend-plugin': + case 'frontend-extension-bundle': case 'frontend-plugin-module': return startFrontend({ entry: 'dev/index', ...options }); case 'frontend-dynamic-container' as PackageRole: // experimental diff --git a/packages/cli/src/lib/bundler/packageDetection.ts b/packages/cli/src/lib/bundler/packageDetection.ts index 0c357fe79e..5fa49c66ef 100644 --- a/packages/cli/src/lib/bundler/packageDetection.ts +++ b/packages/cli/src/lib/bundler/packageDetection.ts @@ -84,9 +84,11 @@ async function detectPackages( { paths: [targetPath] }, )); if ( - ['frontend-plugin', 'frontend-plugin-module'].includes( - depPackageJson.backstage?.role ?? '', - ) + [ + 'frontend-plugin', + 'frontend-extension-bundle', + 'frontend-plugin-module', + ].includes(depPackageJson.backstage?.role ?? '') ) { // Include alpha entry point if available. If there's no default export it will be ignored const exp = depPackageJson.exports; diff --git a/packages/eslint-plugin/rules/no-undeclared-imports.js b/packages/eslint-plugin/rules/no-undeclared-imports.js index d2c92ccb8a..8810f62faf 100644 --- a/packages/eslint-plugin/rules/no-undeclared-imports.js +++ b/packages/eslint-plugin/rules/no-undeclared-imports.js @@ -48,6 +48,7 @@ function getExpectedDepType( case 'common-library': case 'web-library': case 'frontend-plugin': + case 'frontend-extension-bundle': case 'frontend-plugin-module': case 'node-library': case 'backend-plugin': diff --git a/scripts/list-no-top-level-material-ui-4-imports.js b/scripts/list-no-top-level-material-ui-4-imports.js index a963b0c0b2..ef61125bf8 100644 --- a/scripts/list-no-top-level-material-ui-4-imports.js +++ b/scripts/list-no-top-level-material-ui-4-imports.js @@ -25,7 +25,11 @@ async function main() { for (const pkg of packages) { pkgRole = pkg.packageJson.backstage?.role; - if (pkgRole === 'frontend-plugin' || pkgRole === 'web-library') { + if ( + pkgRole === 'frontend-plugin' || + pkgRole === 'web-library' || + pkgRole === 'frontend-extension-bundle' + ) { const depKeys = Object.keys(pkg.packageJson.dependencies); if (depKeys.findIndex(d => d.includes('@material-ui')) !== -1) { const eslintrcPath = join(pkg.dir, '.eslintrc.js'); diff --git a/scripts/verify-local-dependencies.js b/scripts/verify-local-dependencies.js index 963bc40c9c..e30028a0d7 100755 --- a/scripts/verify-local-dependencies.js +++ b/scripts/verify-local-dependencies.js @@ -41,7 +41,12 @@ const roleRules = [ }, { sourceRole: ['backend-plugin', 'node-library', 'backend-plugin-module'], - targetRole: ['frontend-plugin', 'web-library'], + targetRole: [ + 'frontend-plugin', + 'web-library', + 'frontend-plugin-module', + 'frontend-extension-bundle', + ], message: `Package SOURCE_NAME with backend role SOURCE_ROLE has a dependency on package TARGET_NAME with frontend role TARGET_ROLE, which is not permitted`, }, { @@ -49,6 +54,8 @@ const roleRules = [ targetRole: [ 'frontend-plugin', 'web-library', + 'frontend-plugin-module', + 'frontend-extension-bundle', 'backend-plugin', 'node-library', 'backend-plugin-module', @@ -57,7 +64,11 @@ const roleRules = [ }, { sourceRole: ['frontend-plugin', 'web-library'], - targetRole: 'frontend-plugin', + targetRole: [ + 'frontend-plugin', + 'frontend-plugin-module', + 'frontend-extension-bundle', + ], except: [ // TODO(freben): Address these '@backstage/plugin-api-docs', From 0f7452c03062d59248302552c5ebb11cd8c6b664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 9 Aug 2024 16:42:10 +0200 Subject: [PATCH 2/4] add example package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/cold-tomatoes-vanish.md | 2 +- docs/tooling/cli/02-build-system.md | 26 ++++----- .../app-next-example-extensions/.eslintrc.js | 1 + .../app-next-example-extensions/README.md | 3 + .../catalog-info.yaml | 9 +++ .../app-next-example-extensions/package.json | 55 +++++++++++++++++++ .../src/dummy.test.ts | 21 +++++++ .../src/extensions}/HomePage.tsx | 17 ++++++ .../src/extensions/NotFoundErrorPage.tsx} | 4 +- .../src/extensions/ScmAuthApi.ts | 22 ++++++++ .../src/extensions/ScmIntegrationApi.ts} | 24 ++++---- .../src/extensions/SignInPage.tsx | 26 +++++++++ .../src/extensions/index.ts | 21 +++++++ .../app-next-example-extensions/src/index.ts | 24 ++++++++ .../src/setupTests.ts | 17 ++++++ packages/app-next/package.json | 1 + packages/app-next/src/App.tsx | 55 +------------------ .../src/index-public-experimental.tsx | 5 +- packages/app/src/App.tsx | 2 + packages/cli-node/src/roles/PackageRoles.ts | 2 +- packages/cli-node/src/roles/types.ts | 2 +- packages/cli/config/eslint-factory.js | 2 +- packages/cli/config/jest.js | 2 +- packages/cli/src/commands/repo/fix.ts | 4 +- packages/cli/src/commands/start/command.ts | 2 +- .../cli/src/lib/bundler/packageDetection.ts | 2 +- .../rules/no-undeclared-imports.js | 2 +- ...list-no-top-level-material-ui-4-imports.js | 2 +- scripts/verify-local-dependencies.js | 6 +- yarn.lock | 29 ++++++++++ 30 files changed, 295 insertions(+), 95 deletions(-) create mode 100644 packages/app-next-example-extensions/.eslintrc.js create mode 100644 packages/app-next-example-extensions/README.md create mode 100644 packages/app-next-example-extensions/catalog-info.yaml create mode 100644 packages/app-next-example-extensions/package.json create mode 100644 packages/app-next-example-extensions/src/dummy.test.ts rename packages/{app-next/src => app-next-example-extensions/src/extensions}/HomePage.tsx (84%) rename packages/{app-next/src/examples/notFoundErrorPageExtension.tsx => app-next-example-extensions/src/extensions/NotFoundErrorPage.tsx} (94%) create mode 100644 packages/app-next-example-extensions/src/extensions/ScmAuthApi.ts rename packages/{app-next/src/overrides/SignInPage.tsx => app-next-example-extensions/src/extensions/ScmIntegrationApi.ts} (63%) create mode 100644 packages/app-next-example-extensions/src/extensions/SignInPage.tsx create mode 100644 packages/app-next-example-extensions/src/extensions/index.ts create mode 100644 packages/app-next-example-extensions/src/index.ts create mode 100644 packages/app-next-example-extensions/src/setupTests.ts diff --git a/.changeset/cold-tomatoes-vanish.md b/.changeset/cold-tomatoes-vanish.md index a6b34504c7..729ff2ecb5 100644 --- a/.changeset/cold-tomatoes-vanish.md +++ b/.changeset/cold-tomatoes-vanish.md @@ -4,4 +4,4 @@ '@backstage/eslint-plugin': patch --- -Added support for the `frontend-extension-bundle` role, which is used in conjunction with the new frontend system to ship extensions to your apps. +Added support for the `frontend-extensions-bundle` role, which is used in conjunction with the new frontend system to ship extensions to your apps. diff --git a/docs/tooling/cli/02-build-system.md b/docs/tooling/cli/02-build-system.md index 1c850c7048..5cc672788e 100644 --- a/docs/tooling/cli/02-build-system.md +++ b/docs/tooling/cli/02-build-system.md @@ -93,19 +93,19 @@ defined in the `package.json` of each package like this: These are the available roles that are currently supported by the Backstage build system: -| Role | Description | Example | -| ------------------------- | -------------------------------------------- | -------------------------------------------- | -| frontend | Bundled frontend application | `packages/app` | -| backend | Bundled backend application | `packages/backend` | -| cli | Package used as a command-line interface | `@backstage/cli`, `@backstage/codemods` | -| web-library | Web library for use by other packages | `@backstage/plugin-catalog-react` | -| node-library | Node.js library for use by other packages | `@backstage/plugin-techdocs-node` | -| common-library | Isomorphic library for use by other packages | `@backstage/plugin-permission-common` | -| frontend-plugin | Backstage frontend plugin | `@backstage/plugin-scaffolder` | -| frontend-extension-bundle | Extensions for the Backstage frontend | Typically only appears in adopter repos | -| frontend-plugin-module | Backstage frontend plugin module | `@backstage/plugin-analytics-module-ga` | -| backend-plugin | Backstage backend plugin | `@backstage/plugin-auth-backend` | -| backend-plugin-module | Backstage backend plugin module | `@backstage/plugin-search-backend-module-pg` | +| Role | Description | Example | +| -------------------------- | -------------------------------------------- | -------------------------------------------- | +| frontend | Bundled frontend application | `packages/app` | +| backend | Bundled backend application | `packages/backend` | +| cli | Package used as a command-line interface | `@backstage/cli`, `@backstage/codemods` | +| web-library | Web library for use by other packages | `@backstage/plugin-catalog-react` | +| node-library | Node.js library for use by other packages | `@backstage/plugin-techdocs-node` | +| common-library | Isomorphic library for use by other packages | `@backstage/plugin-permission-common` | +| frontend-plugin | Backstage frontend plugin | `@backstage/plugin-scaffolder` | +| frontend-extensions-bundle | Extensions for the Backstage frontend | Typically only appears in adopter repos | +| frontend-plugin-module | Backstage frontend plugin module | `@backstage/plugin-analytics-module-ga` | +| backend-plugin | Backstage backend plugin | `@backstage/plugin-auth-backend` | +| backend-plugin-module | Backstage backend plugin module | `@backstage/plugin-search-backend-module-pg` | Most of the steps that we cover below have an accompanying command that is intended to be used as a package script. The commands are all available under the `backstage-cli package` category, and many of the commands will behave differently depending on the role of the package. The commands are intended to be used like this: diff --git a/packages/app-next-example-extensions/.eslintrc.js b/packages/app-next-example-extensions/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/packages/app-next-example-extensions/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/packages/app-next-example-extensions/README.md b/packages/app-next-example-extensions/README.md new file mode 100644 index 0000000000..0c875f419d --- /dev/null +++ b/packages/app-next-example-extensions/README.md @@ -0,0 +1,3 @@ +# app-next-example-extensions + +This is just an example of how extensions can be bundled up for adding into your Backstage frontend app. diff --git a/packages/app-next-example-extensions/catalog-info.yaml b/packages/app-next-example-extensions/catalog-info.yaml new file mode 100644 index 0000000000..43fe837fe0 --- /dev/null +++ b/packages/app-next-example-extensions/catalog-info.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: internal-app-next-example-extensions + title: '@internal/app-next-example-extensions' +spec: + lifecycle: experimental + type: backstage-frontend-extensions-bundle + owner: maintainers diff --git a/packages/app-next-example-extensions/package.json b/packages/app-next-example-extensions/package.json new file mode 100644 index 0000000000..b888c0a57d --- /dev/null +++ b/packages/app-next-example-extensions/package.json @@ -0,0 +1,55 @@ +{ + "name": "@internal/app-next-example-extensions", + "version": "0.0.0", + "private": true, + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-extensions-bundle" + }, + "sideEffects": false, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/core-components": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", + "@backstage/integration-react": "workspace:^", + "@backstage/plugin-home": "workspace:^", + "@backstage/theme": "workspace:^", + "@material-ui/core": "^4.9.13", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.61", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^15.0.0", + "@testing-library/user-event": "^14.0.0", + "msw": "^1.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/packages/app-next-example-extensions/src/dummy.test.ts b/packages/app-next-example-extensions/src/dummy.test.ts new file mode 100644 index 0000000000..0744a7f13d --- /dev/null +++ b/packages/app-next-example-extensions/src/dummy.test.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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. + */ + +describe('dummy', () => { + it('succeeds', () => { + expect(true).toBe(true); + }); +}); diff --git a/packages/app-next/src/HomePage.tsx b/packages/app-next-example-extensions/src/extensions/HomePage.tsx similarity index 84% rename from packages/app-next/src/HomePage.tsx rename to packages/app-next-example-extensions/src/extensions/HomePage.tsx index d6ee5cbb04..395c4e81dd 100644 --- a/packages/app-next/src/HomePage.tsx +++ b/packages/app-next-example-extensions/src/extensions/HomePage.tsx @@ -29,6 +29,11 @@ import { import { Content, Header, Page } from '@backstage/core-components'; import React from 'react'; import HomeIcon from '@material-ui/icons/Home'; +import { + coreExtensionData, + createExtension, +} from '@backstage/frontend-plugin-api'; +import { titleExtensionDataRef } from '@backstage/plugin-home/alpha'; const clockConfigs: ClockConfig[] = [ { @@ -111,3 +116,15 @@ export const homePage = ( ); + +export const HomePage = createExtension({ + name: 'myhomepage', + attachTo: { id: 'page:home', input: 'props' }, + output: { + children: coreExtensionData.reactElement, + title: titleExtensionDataRef, + }, + factory() { + return { children: homePage, title: 'just a title' }; + }, +}); diff --git a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx b/packages/app-next-example-extensions/src/extensions/NotFoundErrorPage.tsx similarity index 94% rename from packages/app-next/src/examples/notFoundErrorPageExtension.tsx rename to packages/app-next-example-extensions/src/extensions/NotFoundErrorPage.tsx index f5108c6c15..e37b0966c6 100644 --- a/packages/app-next/src/examples/notFoundErrorPageExtension.tsx +++ b/packages/app-next-example-extensions/src/extensions/NotFoundErrorPage.tsx @@ -23,7 +23,7 @@ import Box from '@material-ui/core/Box'; import Typography from '@material-ui/core/Typography'; import { Button } from '@backstage/core-components'; -export function CustomNotFoundErrorPage() { +function CustomNotFoundErrorPage() { return ( CustomNotFoundErrorPage }, }); diff --git a/packages/app-next-example-extensions/src/extensions/ScmAuthApi.ts b/packages/app-next-example-extensions/src/extensions/ScmAuthApi.ts new file mode 100644 index 0000000000..5896ff960a --- /dev/null +++ b/packages/app-next-example-extensions/src/extensions/ScmAuthApi.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 { createApiExtension } from '@backstage/frontend-plugin-api'; +import { ScmAuth } from '@backstage/integration-react'; + +export const ScmAuthApi = createApiExtension({ + factory: ScmAuth.createDefaultApiFactory(), +}); diff --git a/packages/app-next/src/overrides/SignInPage.tsx b/packages/app-next-example-extensions/src/extensions/ScmIntegrationApi.ts similarity index 63% rename from packages/app-next/src/overrides/SignInPage.tsx rename to packages/app-next-example-extensions/src/extensions/ScmIntegrationApi.ts index 364a749293..022f1e599e 100644 --- a/packages/app-next/src/overrides/SignInPage.tsx +++ b/packages/app-next-example-extensions/src/extensions/ScmIntegrationApi.ts @@ -14,18 +14,20 @@ * limitations under the License. */ -import React from 'react'; -import { SignInPage } from '@backstage/core-components'; import { - createExtensionOverrides, - createSignInPageExtension, + configApiRef, + createApiExtension, + createApiFactory, } from '@backstage/frontend-plugin-api'; +import { + ScmIntegrationsApi, + scmIntegrationsApiRef, +} from '@backstage/integration-react'; -const signInPage = createSignInPageExtension({ - name: 'guest', - loader: async () => props => , -}); - -export const signInPageOverrides = createExtensionOverrides({ - extensions: [signInPage], +export const ScmIntegrationApi = createApiExtension({ + factory: createApiFactory({ + api: scmIntegrationsApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), + }), }); diff --git a/packages/app-next-example-extensions/src/extensions/SignInPage.tsx b/packages/app-next-example-extensions/src/extensions/SignInPage.tsx new file mode 100644 index 0000000000..69a2f70e97 --- /dev/null +++ b/packages/app-next-example-extensions/src/extensions/SignInPage.tsx @@ -0,0 +1,26 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 React from 'react'; +import { createSignInPageExtension } from '@backstage/frontend-plugin-api'; + +export const SignInPage = createSignInPageExtension({ + name: 'guest', + loader: () => + import('@backstage/core-components').then(m => props => ( + + )), +}); diff --git a/packages/app-next-example-extensions/src/extensions/index.ts b/packages/app-next-example-extensions/src/extensions/index.ts new file mode 100644 index 0000000000..d1845405af --- /dev/null +++ b/packages/app-next-example-extensions/src/extensions/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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. + */ + +export { HomePage } from './HomePage'; +export { NotFoundErrorPage } from './NotFoundErrorPage'; +export { ScmAuthApi } from './ScmAuthApi'; +export { ScmIntegrationApi } from './ScmIntegrationApi'; +export { SignInPage } from './SignInPage'; diff --git a/packages/app-next-example-extensions/src/index.ts b/packages/app-next-example-extensions/src/index.ts new file mode 100644 index 0000000000..aa61e9181a --- /dev/null +++ b/packages/app-next-example-extensions/src/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 { createExtensionOverrides } from '@backstage/frontend-plugin-api'; +import * as extensions from './extensions'; + +export { SignInPage } from './extensions/SignInPage'; + +export default createExtensionOverrides({ + extensions: Object.values(extensions), +}); diff --git a/packages/app-next-example-extensions/src/setupTests.ts b/packages/app-next-example-extensions/src/setupTests.ts new file mode 100644 index 0000000000..91af6695ac --- /dev/null +++ b/packages/app-next-example-extensions/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 '@testing-library/jest-dom'; diff --git a/packages/app-next/package.json b/packages/app-next/package.json index a12371a135..2d0d4290e9 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -49,6 +49,7 @@ "@backstage/plugin-techdocs-react": "workspace:^", "@backstage/plugin-user-settings": "workspace:^", "@backstage/theme": "workspace:^", + "@internal/app-next-example-extensions": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index b57c680474..9ac0b6e335 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -17,33 +17,16 @@ import React from 'react'; import { createApp } from '@backstage/frontend-app-api'; import { pagesPlugin } from './examples/pagesPlugin'; -import notFoundErrorPage from './examples/notFoundErrorPageExtension'; import userSettingsPlugin from '@backstage/plugin-user-settings/alpha'; -import homePlugin, { - titleExtensionDataRef, -} from '@backstage/plugin-home/alpha'; - -import { - coreExtensionData, - createExtension, - createApiExtension, - createExtensionOverrides, -} from '@backstage/frontend-plugin-api'; +import homePlugin from '@backstage/plugin-home/alpha'; import techdocsPlugin from '@backstage/plugin-techdocs/alpha'; import appVisualizerPlugin from '@backstage/plugin-app-visualizer'; -import { homePage } from './HomePage'; import { convertLegacyApp } from '@backstage/core-compat-api'; import { FlatRoutes } from '@backstage/core-app-api'; import { Route } from 'react-router'; import { CatalogImportPage } from '@backstage/plugin-catalog-import'; -import { createApiFactory, configApiRef } from '@backstage/core-plugin-api'; -import { - ScmAuth, - ScmIntegrationsApi, - scmIntegrationsApiRef, -} from '@backstage/integration-react'; import kubernetesPlugin from '@backstage/plugin-kubernetes/alpha'; -import { signInPageOverrides } from './overrides/SignInPage'; +import extensions from '@internal/app-next-example-extensions'; /* @@ -74,30 +57,6 @@ TODO: /* app.tsx */ -const homePageExtension = createExtension({ - name: 'myhomepage', - attachTo: { id: 'page:home', input: 'props' }, - output: { - children: coreExtensionData.reactElement, - title: titleExtensionDataRef, - }, - factory() { - return { children: homePage, title: 'just a title' }; - }, -}); - -const scmAuthExtension = createApiExtension({ - factory: ScmAuth.createDefaultApiFactory(), -}); - -const scmIntegrationApi = createApiExtension({ - factory: createApiFactory({ - api: scmIntegrationsApiRef, - deps: { configApi: configApiRef }, - factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), - }), -}); - const collectedLegacyPlugins = convertLegacyApp( } /> @@ -112,16 +71,8 @@ const app = createApp({ homePlugin, appVisualizerPlugin, kubernetesPlugin, - signInPageOverrides, + extensions, ...collectedLegacyPlugins, - createExtensionOverrides({ - extensions: [ - homePageExtension, - scmAuthExtension, - scmIntegrationApi, - notFoundErrorPage, - ], - }), ], /* Handled through config instead */ // bindRoutes({ bind }) { diff --git a/packages/app-next/src/index-public-experimental.tsx b/packages/app-next/src/index-public-experimental.tsx index 56bc698ffd..c2825203be 100644 --- a/packages/app-next/src/index-public-experimental.tsx +++ b/packages/app-next/src/index-public-experimental.tsx @@ -18,7 +18,7 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import { CookieAuthRedirect } from '@backstage/plugin-auth-react'; import { createApp } from '@backstage/frontend-app-api'; -import { signInPageOverrides } from './overrides/SignInPage'; +import { SignInPage } from '@internal/app-next-example-extensions'; import { coreExtensionData, createExtension, @@ -39,9 +39,8 @@ const authRedirectExtension = createExtension({ const app = createApp({ features: [ - signInPageOverrides, createExtensionOverrides({ - extensions: [authRedirectExtension], + extensions: [SignInPage, authRedirectExtension], }), ], }); diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index d741dea098..ec5256a78e 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -83,6 +83,7 @@ import { customDevToolsPage } from './components/devtools/CustomDevToolsPage'; import { DevToolsPage } from '@backstage/plugin-devtools'; import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unprocessed-entities'; import { NotificationsPage } from '@backstage/plugin-notifications'; +import { AppNextExtensionsPage } from '@backstage/plugin-app-next-extensions'; const app = createApp({ apis, @@ -210,6 +211,7 @@ const routes = ( {customDevToolsPage} } /> + } /> ); diff --git a/packages/cli-node/src/roles/PackageRoles.ts b/packages/cli-node/src/roles/PackageRoles.ts index ebed918193..76114b7261 100644 --- a/packages/cli-node/src/roles/PackageRoles.ts +++ b/packages/cli-node/src/roles/PackageRoles.ts @@ -54,7 +54,7 @@ const packageRoleInfos: PackageRoleInfo[] = [ output: ['types', 'esm'], }, { - role: 'frontend-extension-bundle', + role: 'frontend-extensions-bundle', platform: 'web', output: ['types', 'esm'], }, diff --git a/packages/cli-node/src/roles/types.ts b/packages/cli-node/src/roles/types.ts index fd20a59231..ebb417e614 100644 --- a/packages/cli-node/src/roles/types.ts +++ b/packages/cli-node/src/roles/types.ts @@ -27,7 +27,7 @@ export type PackageRole = | 'node-library' | 'common-library' | 'frontend-plugin' - | 'frontend-extension-bundle' + | 'frontend-extensions-bundle' | 'frontend-plugin-module' | 'backend-plugin' | 'backend-plugin-module'; diff --git a/packages/cli/config/eslint-factory.js b/packages/cli/config/eslint-factory.js index b6d55aa0be..460fa166d1 100644 --- a/packages/cli/config/eslint-factory.js +++ b/packages/cli/config/eslint-factory.js @@ -200,7 +200,7 @@ function createConfigForRole(dir, role, extraConfig = {}) { case 'web-library': case 'frontend': case 'frontend-plugin': - case 'frontend-extension-bundle': + case 'frontend-extensions-bundle': case 'frontend-plugin-module': case 'frontend-dynamic-container': return createConfig(dir, { diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index 1153781af5..22c89f6782 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -54,7 +54,7 @@ function getRoleConfig(role) { case 'web-library': case 'common-library': case 'frontend-plugin': - case 'frontend-extension-bundle': + case 'frontend-extensions-bundle': case 'frontend-plugin-module': return { testEnvironment: require.resolve('jest-environment-jsdom') }; case 'cli': diff --git a/packages/cli/src/commands/repo/fix.ts b/packages/cli/src/commands/repo/fix.ts index c117d9b436..68f857798e 100644 --- a/packages/cli/src/commands/repo/fix.ts +++ b/packages/cli/src/commands/repo/fix.ts @@ -246,7 +246,7 @@ function guessPluginId(role: PackageRole, pkgName: string): string | undefined { case 'frontend': case 'frontend-plugin': return pkgName.match(/plugin-(.*)/)?.[1]; - case 'frontend-extension-bundle': + case 'frontend-extensions-bundle': return undefined; case 'frontend-plugin-module': return pkgName.match(/plugin-(.*)-module-/)?.[1]; @@ -366,7 +366,7 @@ export function fixPluginPackages( role === 'common-library' || role === 'web-library' || role === 'node-library' || - role === 'frontend-extension-bundle' || + role === 'frontend-extensions-bundle' || role === 'frontend-plugin-module' // TODO(Rugvip): Remove this once frontend modules are required to have a plugin ID ) { return; diff --git a/packages/cli/src/commands/start/command.ts b/packages/cli/src/commands/start/command.ts index 3e419f99cf..ac2bb20be7 100644 --- a/packages/cli/src/commands/start/command.ts +++ b/packages/cli/src/commands/start/command.ts @@ -46,7 +46,7 @@ export async function command(opts: OptionValues): Promise { }); case 'web-library': case 'frontend-plugin': - case 'frontend-extension-bundle': + case 'frontend-extensions-bundle': case 'frontend-plugin-module': return startFrontend({ entry: 'dev/index', ...options }); case 'frontend-dynamic-container' as PackageRole: // experimental diff --git a/packages/cli/src/lib/bundler/packageDetection.ts b/packages/cli/src/lib/bundler/packageDetection.ts index 5fa49c66ef..22713ff3c9 100644 --- a/packages/cli/src/lib/bundler/packageDetection.ts +++ b/packages/cli/src/lib/bundler/packageDetection.ts @@ -86,7 +86,7 @@ async function detectPackages( if ( [ 'frontend-plugin', - 'frontend-extension-bundle', + 'frontend-extensions-bundle', 'frontend-plugin-module', ].includes(depPackageJson.backstage?.role ?? '') ) { diff --git a/packages/eslint-plugin/rules/no-undeclared-imports.js b/packages/eslint-plugin/rules/no-undeclared-imports.js index 8810f62faf..7756b82cc2 100644 --- a/packages/eslint-plugin/rules/no-undeclared-imports.js +++ b/packages/eslint-plugin/rules/no-undeclared-imports.js @@ -48,7 +48,7 @@ function getExpectedDepType( case 'common-library': case 'web-library': case 'frontend-plugin': - case 'frontend-extension-bundle': + case 'frontend-extensions-bundle': case 'frontend-plugin-module': case 'node-library': case 'backend-plugin': diff --git a/scripts/list-no-top-level-material-ui-4-imports.js b/scripts/list-no-top-level-material-ui-4-imports.js index ef61125bf8..c92d4515fa 100644 --- a/scripts/list-no-top-level-material-ui-4-imports.js +++ b/scripts/list-no-top-level-material-ui-4-imports.js @@ -28,7 +28,7 @@ async function main() { if ( pkgRole === 'frontend-plugin' || pkgRole === 'web-library' || - pkgRole === 'frontend-extension-bundle' + pkgRole === 'frontend-extensions-bundle' ) { const depKeys = Object.keys(pkg.packageJson.dependencies); if (depKeys.findIndex(d => d.includes('@material-ui')) !== -1) { diff --git a/scripts/verify-local-dependencies.js b/scripts/verify-local-dependencies.js index e30028a0d7..c82e978475 100755 --- a/scripts/verify-local-dependencies.js +++ b/scripts/verify-local-dependencies.js @@ -45,7 +45,7 @@ const roleRules = [ 'frontend-plugin', 'web-library', 'frontend-plugin-module', - 'frontend-extension-bundle', + 'frontend-extensions-bundle', ], message: `Package SOURCE_NAME with backend role SOURCE_ROLE has a dependency on package TARGET_NAME with frontend role TARGET_ROLE, which is not permitted`, }, @@ -55,7 +55,7 @@ const roleRules = [ 'frontend-plugin', 'web-library', 'frontend-plugin-module', - 'frontend-extension-bundle', + 'frontend-extensions-bundle', 'backend-plugin', 'node-library', 'backend-plugin-module', @@ -67,7 +67,7 @@ const roleRules = [ targetRole: [ 'frontend-plugin', 'frontend-plugin-module', - 'frontend-extension-bundle', + 'frontend-extensions-bundle', ], except: [ // TODO(freben): Address these diff --git a/yarn.lock b/yarn.lock index c14251269c..43e8dcfdc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10220,6 +10220,34 @@ __metadata: languageName: node linkType: hard +"@internal/app-next-example-extensions@workspace:^, @internal/app-next-example-extensions@workspace:packages/app-next-example-extensions": + version: 0.0.0-use.local + resolution: "@internal/app-next-example-extensions@workspace:packages/app-next-example-extensions" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/dev-utils": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" + "@backstage/integration-react": "workspace:^" + "@backstage/plugin-home": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" + "@material-ui/core": ^4.9.13 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": ^4.0.0-alpha.61 + "@testing-library/jest-dom": ^6.0.0 + "@testing-library/react": ^15.0.0 + "@testing-library/user-event": ^14.0.0 + msw: ^1.0.0 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + languageName: unknown + linkType: soft + "@internal/plugin-todo-list-backend@workspace:plugins/example-todo-list-backend": version: 0.0.0-use.local resolution: "@internal/plugin-todo-list-backend@workspace:plugins/example-todo-list-backend" @@ -26933,6 +26961,7 @@ __metadata: "@backstage/plugin-user-settings": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" + "@internal/app-next-example-extensions": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 From 705794def590c02a9242b52ee1c76d2097edddfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 12 Aug 2024 10:25:35 +0200 Subject: [PATCH 3/4] rename the role to frontend-extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/cold-tomatoes-vanish.md | 2 +- docs/tooling/cli/02-build-system.md | 26 ++++++------- .../catalog-info.yaml | 2 +- .../app-next-example-extensions/package.json | 38 +++++++++---------- packages/cli-node/src/roles/PackageRoles.ts | 2 +- packages/cli-node/src/roles/types.ts | 2 +- packages/cli/config/eslint-factory.js | 2 +- packages/cli/config/jest.js | 2 +- packages/cli/src/commands/repo/fix.ts | 4 +- packages/cli/src/commands/start/command.ts | 2 +- .../cli/src/lib/bundler/packageDetection.ts | 2 +- .../rules/no-undeclared-imports.js | 2 +- ...list-no-top-level-material-ui-4-imports.js | 2 +- scripts/verify-local-dependencies.js | 6 +-- 14 files changed, 47 insertions(+), 47 deletions(-) diff --git a/.changeset/cold-tomatoes-vanish.md b/.changeset/cold-tomatoes-vanish.md index 729ff2ecb5..1ffd701e9b 100644 --- a/.changeset/cold-tomatoes-vanish.md +++ b/.changeset/cold-tomatoes-vanish.md @@ -4,4 +4,4 @@ '@backstage/eslint-plugin': patch --- -Added support for the `frontend-extensions-bundle` role, which is used in conjunction with the new frontend system to ship extensions to your apps. +Added support for the `frontend-extensions` role, which is used in conjunction with the new frontend system to ship extensions to your apps. diff --git a/docs/tooling/cli/02-build-system.md b/docs/tooling/cli/02-build-system.md index 5cc672788e..ced3385b1e 100644 --- a/docs/tooling/cli/02-build-system.md +++ b/docs/tooling/cli/02-build-system.md @@ -93,19 +93,19 @@ defined in the `package.json` of each package like this: These are the available roles that are currently supported by the Backstage build system: -| Role | Description | Example | -| -------------------------- | -------------------------------------------- | -------------------------------------------- | -| frontend | Bundled frontend application | `packages/app` | -| backend | Bundled backend application | `packages/backend` | -| cli | Package used as a command-line interface | `@backstage/cli`, `@backstage/codemods` | -| web-library | Web library for use by other packages | `@backstage/plugin-catalog-react` | -| node-library | Node.js library for use by other packages | `@backstage/plugin-techdocs-node` | -| common-library | Isomorphic library for use by other packages | `@backstage/plugin-permission-common` | -| frontend-plugin | Backstage frontend plugin | `@backstage/plugin-scaffolder` | -| frontend-extensions-bundle | Extensions for the Backstage frontend | Typically only appears in adopter repos | -| frontend-plugin-module | Backstage frontend plugin module | `@backstage/plugin-analytics-module-ga` | -| backend-plugin | Backstage backend plugin | `@backstage/plugin-auth-backend` | -| backend-plugin-module | Backstage backend plugin module | `@backstage/plugin-search-backend-module-pg` | +| Role | Description | Example | +| ---------------------- | ----------------------------------------------------------------------------- | -------------------------------------------- | +| frontend | Bundled frontend application | `packages/app` | +| backend | Bundled backend application | `packages/backend` | +| cli | Package used as a command-line interface | `@backstage/cli`, `@backstage/codemods` | +| web-library | Web library for use by other packages | `@backstage/plugin-catalog-react` | +| node-library | Node.js library for use by other packages | `@backstage/plugin-techdocs-node` | +| common-library | Isomorphic library for use by other packages | `@backstage/plugin-permission-common` | +| frontend-plugin | Backstage frontend plugin | `@backstage/plugin-scaffolder` | +| frontend-extensions | Extensions (customizations, private additions etc) for the Backstage frontend | Typically only appears in adopter repos | +| frontend-plugin-module | Backstage frontend plugin module | `@backstage/plugin-analytics-module-ga` | +| backend-plugin | Backstage backend plugin | `@backstage/plugin-auth-backend` | +| backend-plugin-module | Backstage backend plugin module | `@backstage/plugin-search-backend-module-pg` | Most of the steps that we cover below have an accompanying command that is intended to be used as a package script. The commands are all available under the `backstage-cli package` category, and many of the commands will behave differently depending on the role of the package. The commands are intended to be used like this: diff --git a/packages/app-next-example-extensions/catalog-info.yaml b/packages/app-next-example-extensions/catalog-info.yaml index 43fe837fe0..32acdd0317 100644 --- a/packages/app-next-example-extensions/catalog-info.yaml +++ b/packages/app-next-example-extensions/catalog-info.yaml @@ -5,5 +5,5 @@ metadata: title: '@internal/app-next-example-extensions' spec: lifecycle: experimental - type: backstage-frontend-extensions-bundle + type: backstage-frontend-extensions owner: maintainers diff --git a/packages/app-next-example-extensions/package.json b/packages/app-next-example-extensions/package.json index b888c0a57d..e4534adcc5 100644 --- a/packages/app-next-example-extensions/package.json +++ b/packages/app-next-example-extensions/package.json @@ -1,27 +1,30 @@ { "name": "@internal/app-next-example-extensions", "version": "0.0.0", - "private": true, - "main": "src/index.ts", - "types": "src/index.ts", - "license": "Apache-2.0", + "backstage": { + "role": "frontend-extensions" + }, "publishConfig": { "access": "public", "main": "dist/index.esm.js", "types": "dist/index.d.ts" }, - "backstage": { - "role": "frontend-extensions-bundle" - }, + "private": true, + "license": "Apache-2.0", "sideEffects": false, + "main": "src/index.ts", + "types": "src/index.ts", + "files": [ + "dist" + ], "scripts": { - "start": "backstage-cli package start", "build": "backstage-cli package build", - "lint": "backstage-cli package lint", - "test": "backstage-cli package test", "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", "prepack": "backstage-cli package prepack", - "postpack": "backstage-cli package postpack" + "postpack": "backstage-cli package postpack", + "start": "backstage-cli package start", + "test": "backstage-cli package test" }, "dependencies": { "@backstage/core-components": "workspace:^", @@ -34,11 +37,6 @@ "@material-ui/lab": "^4.0.0-alpha.61", "react-use": "^17.2.4" }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-router-dom": "6.0.0-beta.0 || ^6.3.0" - }, "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/core-app-api": "workspace:^", @@ -49,7 +47,9 @@ "@testing-library/user-event": "^14.0.0", "msw": "^1.0.0" }, - "files": [ - "dist" - ] + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + } } diff --git a/packages/cli-node/src/roles/PackageRoles.ts b/packages/cli-node/src/roles/PackageRoles.ts index 76114b7261..0a7e6142cf 100644 --- a/packages/cli-node/src/roles/PackageRoles.ts +++ b/packages/cli-node/src/roles/PackageRoles.ts @@ -54,7 +54,7 @@ const packageRoleInfos: PackageRoleInfo[] = [ output: ['types', 'esm'], }, { - role: 'frontend-extensions-bundle', + role: 'frontend-extensions', platform: 'web', output: ['types', 'esm'], }, diff --git a/packages/cli-node/src/roles/types.ts b/packages/cli-node/src/roles/types.ts index ebb417e614..1cd374f1e7 100644 --- a/packages/cli-node/src/roles/types.ts +++ b/packages/cli-node/src/roles/types.ts @@ -27,7 +27,7 @@ export type PackageRole = | 'node-library' | 'common-library' | 'frontend-plugin' - | 'frontend-extensions-bundle' + | 'frontend-extensions' | 'frontend-plugin-module' | 'backend-plugin' | 'backend-plugin-module'; diff --git a/packages/cli/config/eslint-factory.js b/packages/cli/config/eslint-factory.js index 460fa166d1..7a55ad464f 100644 --- a/packages/cli/config/eslint-factory.js +++ b/packages/cli/config/eslint-factory.js @@ -200,7 +200,7 @@ function createConfigForRole(dir, role, extraConfig = {}) { case 'web-library': case 'frontend': case 'frontend-plugin': - case 'frontend-extensions-bundle': + case 'frontend-extensions': case 'frontend-plugin-module': case 'frontend-dynamic-container': return createConfig(dir, { diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index 22c89f6782..8c97516667 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -54,7 +54,7 @@ function getRoleConfig(role) { case 'web-library': case 'common-library': case 'frontend-plugin': - case 'frontend-extensions-bundle': + case 'frontend-extensions': case 'frontend-plugin-module': return { testEnvironment: require.resolve('jest-environment-jsdom') }; case 'cli': diff --git a/packages/cli/src/commands/repo/fix.ts b/packages/cli/src/commands/repo/fix.ts index 68f857798e..d670552bbc 100644 --- a/packages/cli/src/commands/repo/fix.ts +++ b/packages/cli/src/commands/repo/fix.ts @@ -246,7 +246,7 @@ function guessPluginId(role: PackageRole, pkgName: string): string | undefined { case 'frontend': case 'frontend-plugin': return pkgName.match(/plugin-(.*)/)?.[1]; - case 'frontend-extensions-bundle': + case 'frontend-extensions': return undefined; case 'frontend-plugin-module': return pkgName.match(/plugin-(.*)-module-/)?.[1]; @@ -366,7 +366,7 @@ export function fixPluginPackages( role === 'common-library' || role === 'web-library' || role === 'node-library' || - role === 'frontend-extensions-bundle' || + role === 'frontend-extensions' || role === 'frontend-plugin-module' // TODO(Rugvip): Remove this once frontend modules are required to have a plugin ID ) { return; diff --git a/packages/cli/src/commands/start/command.ts b/packages/cli/src/commands/start/command.ts index ac2bb20be7..12631b75b5 100644 --- a/packages/cli/src/commands/start/command.ts +++ b/packages/cli/src/commands/start/command.ts @@ -46,7 +46,7 @@ export async function command(opts: OptionValues): Promise { }); case 'web-library': case 'frontend-plugin': - case 'frontend-extensions-bundle': + case 'frontend-extensions': case 'frontend-plugin-module': return startFrontend({ entry: 'dev/index', ...options }); case 'frontend-dynamic-container' as PackageRole: // experimental diff --git a/packages/cli/src/lib/bundler/packageDetection.ts b/packages/cli/src/lib/bundler/packageDetection.ts index 22713ff3c9..fe362b196d 100644 --- a/packages/cli/src/lib/bundler/packageDetection.ts +++ b/packages/cli/src/lib/bundler/packageDetection.ts @@ -86,7 +86,7 @@ async function detectPackages( if ( [ 'frontend-plugin', - 'frontend-extensions-bundle', + 'frontend-extensions', 'frontend-plugin-module', ].includes(depPackageJson.backstage?.role ?? '') ) { diff --git a/packages/eslint-plugin/rules/no-undeclared-imports.js b/packages/eslint-plugin/rules/no-undeclared-imports.js index 7756b82cc2..76331939df 100644 --- a/packages/eslint-plugin/rules/no-undeclared-imports.js +++ b/packages/eslint-plugin/rules/no-undeclared-imports.js @@ -48,7 +48,7 @@ function getExpectedDepType( case 'common-library': case 'web-library': case 'frontend-plugin': - case 'frontend-extensions-bundle': + case 'frontend-extensions': case 'frontend-plugin-module': case 'node-library': case 'backend-plugin': diff --git a/scripts/list-no-top-level-material-ui-4-imports.js b/scripts/list-no-top-level-material-ui-4-imports.js index c92d4515fa..fc2fc6c92e 100644 --- a/scripts/list-no-top-level-material-ui-4-imports.js +++ b/scripts/list-no-top-level-material-ui-4-imports.js @@ -28,7 +28,7 @@ async function main() { if ( pkgRole === 'frontend-plugin' || pkgRole === 'web-library' || - pkgRole === 'frontend-extensions-bundle' + pkgRole === 'frontend-extensions' ) { const depKeys = Object.keys(pkg.packageJson.dependencies); if (depKeys.findIndex(d => d.includes('@material-ui')) !== -1) { diff --git a/scripts/verify-local-dependencies.js b/scripts/verify-local-dependencies.js index c82e978475..2d38e8dc07 100755 --- a/scripts/verify-local-dependencies.js +++ b/scripts/verify-local-dependencies.js @@ -45,7 +45,7 @@ const roleRules = [ 'frontend-plugin', 'web-library', 'frontend-plugin-module', - 'frontend-extensions-bundle', + 'frontend-extensions', ], message: `Package SOURCE_NAME with backend role SOURCE_ROLE has a dependency on package TARGET_NAME with frontend role TARGET_ROLE, which is not permitted`, }, @@ -55,7 +55,7 @@ const roleRules = [ 'frontend-plugin', 'web-library', 'frontend-plugin-module', - 'frontend-extensions-bundle', + 'frontend-extensions', 'backend-plugin', 'node-library', 'backend-plugin-module', @@ -67,7 +67,7 @@ const roleRules = [ targetRole: [ 'frontend-plugin', 'frontend-plugin-module', - 'frontend-extensions-bundle', + 'frontend-extensions', ], except: [ // TODO(freben): Address these From ee9755ba5b77286e31e7f5952002ade3c0701d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 12 Aug 2024 11:11:11 +0200 Subject: [PATCH 4/4] fixup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../app-next-example-extensions/api-report.md | 26 +++++++++++++++++++ .../app-next-example-extensions/package.json | 5 ++++ .../src/extensions/SignInPage.tsx | 3 +++ packages/app/src/App.tsx | 2 -- packages/cli-node/api-report.md | 2 +- 5 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 packages/app-next-example-extensions/api-report.md diff --git a/packages/app-next-example-extensions/api-report.md b/packages/app-next-example-extensions/api-report.md new file mode 100644 index 0000000000..987e61e067 --- /dev/null +++ b/packages/app-next-example-extensions/api-report.md @@ -0,0 +1,26 @@ +## API Report File for "@internal/app-next-example-extensions" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { AnyExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; +import { ExtensionOverrides } from '@backstage/frontend-plugin-api'; + +// @public (undocumented) +const _default: ExtensionOverrides; +export default _default; + +// @public (undocumented) +export const SignInPage: ExtensionDefinition< + {}, + {}, + AnyExtensionDataRef, + {}, + string | undefined, + string | undefined, + string | undefined +>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/packages/app-next-example-extensions/package.json b/packages/app-next-example-extensions/package.json index e4534adcc5..23a29dc549 100644 --- a/packages/app-next-example-extensions/package.json +++ b/packages/app-next-example-extensions/package.json @@ -10,6 +10,11 @@ "types": "dist/index.d.ts" }, "private": true, + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "packages/app-next-example-extensions" + }, "license": "Apache-2.0", "sideEffects": false, "main": "src/index.ts", diff --git a/packages/app-next-example-extensions/src/extensions/SignInPage.tsx b/packages/app-next-example-extensions/src/extensions/SignInPage.tsx index 69a2f70e97..06bbbd45fb 100644 --- a/packages/app-next-example-extensions/src/extensions/SignInPage.tsx +++ b/packages/app-next-example-extensions/src/extensions/SignInPage.tsx @@ -17,6 +17,9 @@ import React from 'react'; import { createSignInPageExtension } from '@backstage/frontend-plugin-api'; +/** + * @public + */ export const SignInPage = createSignInPageExtension({ name: 'guest', loader: () => diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index ec5256a78e..d741dea098 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -83,7 +83,6 @@ import { customDevToolsPage } from './components/devtools/CustomDevToolsPage'; import { DevToolsPage } from '@backstage/plugin-devtools'; import { CatalogUnprocessedEntitiesPage } from '@backstage/plugin-catalog-unprocessed-entities'; import { NotificationsPage } from '@backstage/plugin-notifications'; -import { AppNextExtensionsPage } from '@backstage/plugin-app-next-extensions'; const app = createApp({ apis, @@ -211,7 +210,6 @@ const routes = ( {customDevToolsPage} } /> - } /> ); diff --git a/packages/cli-node/api-report.md b/packages/cli-node/api-report.md index c07ab1ffcb..e6c081fd9b 100644 --- a/packages/cli-node/api-report.md +++ b/packages/cli-node/api-report.md @@ -154,7 +154,7 @@ export type PackageRole = | 'node-library' | 'common-library' | 'frontend-plugin' - | 'frontend-extension-bundle' + | 'frontend-extensions' | 'frontend-plugin-module' | 'backend-plugin' | 'backend-plugin-module';