Revert "added the frontend-extensions package role"

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-08-13 14:41:20 +02:00
parent 115d684716
commit e910e572e0
31 changed files with 86 additions and 357 deletions
-7
View File
@@ -1,7 +0,0 @@
---
'@backstage/cli-node': patch
'@backstage/cli': patch
'@backstage/eslint-plugin': patch
---
Added support for the `frontend-extensions` role, which is used in conjunction with the new frontend system to ship extensions to your apps.
+12 -13
View File
@@ -93,19 +93,18 @@ 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 | 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` |
| 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` |
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:
@@ -1 +0,0 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
@@ -1,3 +0,0 @@
# app-next-example-extensions
This is just an example of how extensions can be bundled up for adding into your Backstage frontend app.
@@ -1,26 +0,0 @@
## 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)
```
@@ -1,9 +0,0 @@
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
owner: maintainers
@@ -1,60 +0,0 @@
{
"name": "@internal/app-next-example-extensions",
"version": "0.0.0",
"backstage": {
"role": "frontend-extensions"
},
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
"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",
"types": "src/index.ts",
"files": [
"dist"
],
"scripts": {
"build": "backstage-cli package build",
"clean": "backstage-cli package clean",
"lint": "backstage-cli package lint",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack",
"start": "backstage-cli package start",
"test": "backstage-cli package test"
},
"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"
},
"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"
},
"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"
}
}
@@ -1,21 +0,0 @@
/*
* 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);
});
});
@@ -1,22 +0,0 @@
/*
* 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(),
});
@@ -1,29 +0,0 @@
/*
* 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';
/**
* @public
*/
export const SignInPage = createSignInPageExtension({
name: 'guest',
loader: () =>
import('@backstage/core-components').then(m => props => (
<m.SignInPage {...props} providers={['guest']} />
)),
});
@@ -1,21 +0,0 @@
/*
* 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';
@@ -1,24 +0,0 @@
/*
* 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),
});
@@ -1,17 +0,0 @@
/*
* 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';
-1
View File
@@ -49,7 +49,6 @@
"@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",
+52 -3
View File
@@ -17,16 +17,33 @@
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 from '@backstage/plugin-home/alpha';
import homePlugin, {
titleExtensionDataRef,
} from '@backstage/plugin-home/alpha';
import {
coreExtensionData,
createExtension,
createApiExtension,
createExtensionOverrides,
} from '@backstage/frontend-plugin-api';
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 extensions from '@internal/app-next-example-extensions';
import { signInPageOverrides } from './overrides/SignInPage';
/*
@@ -57,6 +74,30 @@ 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(
<FlatRoutes>
<Route path="/catalog-import" element={<CatalogImportPage />} />
@@ -71,8 +112,16 @@ const app = createApp({
homePlugin,
appVisualizerPlugin,
kubernetesPlugin,
extensions,
signInPageOverrides,
...collectedLegacyPlugins,
createExtensionOverrides({
extensions: [
homePageExtension,
scmAuthExtension,
scmIntegrationApi,
notFoundErrorPage,
],
}),
],
/* Handled through config instead */
// bindRoutes({ bind }) {
@@ -29,11 +29,6 @@ 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[] = [
{
@@ -116,15 +111,3 @@ export const homePage = (
</Content>
</Page>
);
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' };
},
});
@@ -23,7 +23,7 @@ import Box from '@material-ui/core/Box';
import Typography from '@material-ui/core/Typography';
import { Button } from '@backstage/core-components';
function CustomNotFoundErrorPage() {
export function CustomNotFoundErrorPage() {
return (
<Box
component="article"
@@ -51,7 +51,7 @@ function CustomNotFoundErrorPage() {
);
}
export const NotFoundErrorPage = createComponentExtension({
export default createComponentExtension({
ref: coreComponentRefs.notFoundErrorPage,
loader: { sync: () => CustomNotFoundErrorPage },
});
@@ -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 { SignInPage } from '@internal/app-next-example-extensions';
import { signInPageOverrides } from './overrides/SignInPage';
import {
coreExtensionData,
createExtension,
@@ -39,8 +39,9 @@ const authRedirectExtension = createExtension({
const app = createApp({
features: [
signInPageOverrides,
createExtensionOverrides({
extensions: [SignInPage, authRedirectExtension],
extensions: [authRedirectExtension],
}),
],
});
@@ -14,20 +14,18 @@
* limitations under the License.
*/
import React from 'react';
import { SignInPage } from '@backstage/core-components';
import {
configApiRef,
createApiExtension,
createApiFactory,
createExtensionOverrides,
createSignInPageExtension,
} from '@backstage/frontend-plugin-api';
import {
ScmIntegrationsApi,
scmIntegrationsApiRef,
} from '@backstage/integration-react';
export const ScmIntegrationApi = createApiExtension({
factory: createApiFactory({
api: scmIntegrationsApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi),
}),
const signInPage = createSignInPageExtension({
name: 'guest',
loader: async () => props => <SignInPage {...props} providers={['guest']} />,
});
export const signInPageOverrides = createExtensionOverrides({
extensions: [signInPage],
});
-1
View File
@@ -154,7 +154,6 @@ export type PackageRole =
| 'node-library'
| 'common-library'
| 'frontend-plugin'
| 'frontend-extensions'
| 'frontend-plugin-module'
| 'backend-plugin'
| 'backend-plugin-module';
@@ -53,11 +53,6 @@ const packageRoleInfos: PackageRoleInfo[] = [
platform: 'web',
output: ['types', 'esm'],
},
{
role: 'frontend-extensions',
platform: 'web',
output: ['types', 'esm'],
},
{
role: 'frontend-plugin-module',
platform: 'web',
-1
View File
@@ -27,7 +27,6 @@ export type PackageRole =
| 'node-library'
| 'common-library'
| 'frontend-plugin'
| 'frontend-extensions'
| 'frontend-plugin-module'
| 'backend-plugin'
| 'backend-plugin-module';
-1
View File
@@ -200,7 +200,6 @@ function createConfigForRole(dir, role, extraConfig = {}) {
case 'web-library':
case 'frontend':
case 'frontend-plugin':
case 'frontend-extensions':
case 'frontend-plugin-module':
case 'frontend-dynamic-container':
return createConfig(dir, {
-1
View File
@@ -54,7 +54,6 @@ function getRoleConfig(role) {
case 'web-library':
case 'common-library':
case 'frontend-plugin':
case 'frontend-extensions':
case 'frontend-plugin-module':
return { testEnvironment: require.resolve('jest-environment-jsdom') };
case 'cli':
-3
View File
@@ -246,8 +246,6 @@ function guessPluginId(role: PackageRole, pkgName: string): string | undefined {
case 'frontend':
case 'frontend-plugin':
return pkgName.match(/plugin-(.*)/)?.[1];
case 'frontend-extensions':
return undefined;
case 'frontend-plugin-module':
return pkgName.match(/plugin-(.*)-module-/)?.[1];
case 'backend-plugin':
@@ -366,7 +364,6 @@ export function fixPluginPackages(
role === 'common-library' ||
role === 'web-library' ||
role === 'node-library' ||
role === 'frontend-extensions' ||
role === 'frontend-plugin-module' // TODO(Rugvip): Remove this once frontend modules are required to have a plugin ID
) {
return;
@@ -46,7 +46,6 @@ export async function command(opts: OptionValues): Promise<void> {
});
case 'web-library':
case 'frontend-plugin':
case 'frontend-extensions':
case 'frontend-plugin-module':
return startFrontend({ entry: 'dev/index', ...options });
case 'frontend-dynamic-container' as PackageRole: // experimental
@@ -84,11 +84,9 @@ async function detectPackages(
{ paths: [targetPath] },
));
if (
[
'frontend-plugin',
'frontend-extensions',
'frontend-plugin-module',
].includes(depPackageJson.backstage?.role ?? '')
['frontend-plugin', '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;
@@ -48,7 +48,6 @@ function getExpectedDepType(
case 'common-library':
case 'web-library':
case 'frontend-plugin':
case 'frontend-extensions':
case 'frontend-plugin-module':
case 'node-library':
case 'backend-plugin':
@@ -25,11 +25,7 @@ async function main() {
for (const pkg of packages) {
pkgRole = pkg.packageJson.backstage?.role;
if (
pkgRole === 'frontend-plugin' ||
pkgRole === 'web-library' ||
pkgRole === 'frontend-extensions'
) {
if (pkgRole === 'frontend-plugin' || pkgRole === 'web-library') {
const depKeys = Object.keys(pkg.packageJson.dependencies);
if (depKeys.findIndex(d => d.includes('@material-ui')) !== -1) {
const eslintrcPath = join(pkg.dir, '.eslintrc.js');
+2 -13
View File
@@ -41,12 +41,7 @@ const roleRules = [
},
{
sourceRole: ['backend-plugin', 'node-library', 'backend-plugin-module'],
targetRole: [
'frontend-plugin',
'web-library',
'frontend-plugin-module',
'frontend-extensions',
],
targetRole: ['frontend-plugin', 'web-library'],
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`,
},
{
@@ -54,8 +49,6 @@ const roleRules = [
targetRole: [
'frontend-plugin',
'web-library',
'frontend-plugin-module',
'frontend-extensions',
'backend-plugin',
'node-library',
'backend-plugin-module',
@@ -64,11 +57,7 @@ const roleRules = [
},
{
sourceRole: ['frontend-plugin', 'web-library'],
targetRole: [
'frontend-plugin',
'frontend-plugin-module',
'frontend-extensions',
],
targetRole: 'frontend-plugin',
except: [
// TODO(freben): Address these
'@backstage/plugin-api-docs',
-29
View File
@@ -10222,34 +10222,6 @@ __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"
@@ -26970,7 +26942,6 @@ __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