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',