elevate app.packages to no longer be experimental

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2025-08-07 16:57:41 +02:00
parent e9efcfe64a
commit 8b1bf6e069
16 changed files with 110 additions and 111 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-catalog-graph': patch
'@backstage/plugin-api-docs': patch
'@backstage/plugin-org': patch
---
Updated README instructions for the new frontend system
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/frontend-defaults': patch
'@backstage/frontend-app-api': patch
'@backstage/cli': patch
---
Deprecated new frontend system config setting `app.experimental.packages` to just `app.packages`. The old config will continue working for the time being, but may be removed in a future release.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Updated the `app.packages` config setting now that it no longer is experimental
+1 -2
View File
@@ -1,8 +1,7 @@
app:
title: Backstage Example App
baseUrl: http://localhost:3000
experimental:
packages: all # ✨
packages: all # ✨
#datadogRum:
# clientToken: '123456789'
+11 -14
View File
@@ -48,31 +48,28 @@ App feature discovery lets you automatically discover and install features provi
Because feature discovery needs to interact with the compilation process, it is only available when using the `@backstage/cli` to build your app. It is hooked into the WebPack compilation process by scanning your app package for compatible dependencies, which are then made part of the app compilation bundle.
Since the `@backstage/cli` is a more stable component than the new frontend system, feature discovery is currently marked as an experimental feature of the CLI and needs to be enabled manually. To enable it, add the following configuration to your `app-config.yaml`:
To enable frontend feature discovery, add the following configuration to your `app-config.yaml`:
```yaml
app:
experimental:
packages: all
packages: all
```
This will cause all dependencies in your app package to be installed automatically. If this is not desired, you can use include or exclude filters to narrow down the set of packages:
```yaml
app:
experimental:
packages:
# Only the following packages will be included
include:
- '@backstage/plugin-catalog'
- '@backstage/plugin-scaffolder'
packages:
# Only the following packages will be included
include:
- '@backstage/plugin-catalog'
- '@backstage/plugin-scaffolder'
---
app:
experimental:
packages:
# All but the following package will be included
exclude:
- '@backstage/plugin-catalog'
packages:
# All but the following package will be included
exclude:
- '@backstage/plugin-catalog'
```
Note that you do not need to manually exclude packages that you also import explicitly in code, since plugin instances are deduplicated by the app. You will never end up with duplicate plugin installations except if they are in fact two different plugin instances with different IDs.
@@ -244,8 +244,7 @@ Plugins don't even have to be imported manually after installing their package i
```yaml title="in app-config.yaml"
app:
# Enabling plugin and override features discovery
experimental:
packages: all # ✨
packages: all # ✨
```
### `featureFlags`
+1 -2
View File
@@ -1,6 +1,5 @@
app:
experimental:
packages: 'all' # ✨
packages: 'all' # ✨
routes:
bindings:
@@ -32,7 +32,10 @@ interface PackageDetectionConfig {
function readPackageDetectionConfig(
config: Config,
): PackageDetectionConfig | undefined {
const packages = config.getOptional('app.experimental.packages');
// The experimental key is deprecated, but supported still for backwards compatibility
const packages =
config.getOptional('app.packages') ??
config.getOptional('app.experimental.packages');
if (packages === undefined || packages === null) {
return undefined;
}
@@ -40,21 +43,16 @@ function readPackageDetectionConfig(
if (typeof packages === 'string') {
if (packages !== 'all') {
throw new Error(
`Invalid app.experimental.packages mode, got '${packages}', expected 'all'`,
`Invalid app.packages mode, got '${packages}', expected 'all'`,
);
}
return {};
}
if (typeof packages !== 'object' || Array.isArray(packages)) {
throw new Error(
"Invalid config at 'app.experimental.packages', expected object",
);
throw new Error("Invalid config at 'app.packages', expected object");
}
const packagesConfig = new ConfigReader(
packages,
'app.experimental.packages',
);
const packagesConfig = new ConfigReader(packages, 'app.packages');
return {
include: packagesConfig.getOptionalStringArray('include'),
@@ -2,8 +2,7 @@ app:
title: Scaffolded Backstage App
baseUrl: http://localhost:3000
experimental:
packages: all
packages: all
extensions:
# Disable the nav items that we're manually rendering in packages/app/src/modules/nav/Sidebar.tsx
+17
View File
@@ -20,10 +20,27 @@ export interface Config {
/**
* @visibility frontend
* @deepVisibility frontend
* @deprecated This is no longer experimental; use `app.packages` instead.
*/
packages?: 'all' | { include?: string[]; exclude?: string[] };
};
/**
* Controls what packages are loaded by the new frontend system.
*
* @remarks
*
* When using the 'all' option, all feature packages that were added as
* dependencies to the app will be loaded automatically.
*
* The `include` and `exclude` options can be used to more finely control
* which individual package names to include or exclude.
*
* @visibility frontend
* @deepVisibility frontend
*/
packages?: 'all' | { include?: string[]; exclude?: string[] };
routes?: {
/**
* Maps external route references to regular route references. Both the
@@ -27,7 +27,7 @@ Object.defineProperty(global, '__@backstage/discovered__', {
});
const config = new ConfigReader({
app: { experimental: { packages: 'all' } },
app: { packages: 'all' },
});
describe('discoverAvailableFeatures', () => {
+7 -9
View File
@@ -26,7 +26,10 @@ interface DiscoveryGlobal {
}
function readPackageDetectionConfig(config: Config) {
const packages = config.getOptional('app.experimental.packages');
// The experimental key is deprecated, but supported still for backwards compatibility
const packages =
config.getOptional('app.packages') ??
config.getOptional('app.experimental.packages');
if (packages === undefined || packages === null) {
return undefined;
}
@@ -34,21 +37,16 @@ function readPackageDetectionConfig(config: Config) {
if (typeof packages === 'string') {
if (packages !== 'all') {
throw new Error(
`Invalid app.experimental.packages mode, got '${packages}', expected 'all'`,
`Invalid app.packages mode, got '${packages}', expected 'all'`,
);
}
return {};
}
if (typeof packages !== 'object' || Array.isArray(packages)) {
throw new Error(
"Invalid config at 'app.experimental.packages', expected object",
);
throw new Error("Invalid config at 'app.packages', expected object");
}
const packagesConfig = new ConfigReader(
packages,
'app.experimental.packages',
);
const packagesConfig = new ConfigReader(packages, 'app.packages');
return {
include: packagesConfig.getOptionalStringArray('include'),
@@ -127,10 +127,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -204,10 +202,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -330,10 +326,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -447,10 +441,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -540,10 +532,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -604,10 +594,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -653,10 +641,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -759,10 +745,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -889,10 +873,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -1002,10 +984,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
@@ -1112,10 +1092,8 @@ describe('dynamicFrontendFeaturesLoader', () => {
config: mockApis.config({
data: {
app: {
experimental: {
packages: {
include: [],
},
packages: {
include: [],
},
},
backend: {
+2 -3
View File
@@ -68,9 +68,8 @@ To link that a component provides or consumes an API, see the [`providesApis`](h
```yaml
# app-config.yaml
app:
experimental:
# Auto discovering all plugins extensions
packages: all
# Auto discovering all plugins extensions
packages: all
extensions:
# Enabling some entity cards
# The cards will be displayed in the same order it appears in this setting list
+18 -20
View File
@@ -36,18 +36,18 @@ This plugin installation requires the following steps:
1. Add the `@backstage/catalog-graph` dependency to your app `package.json` file and install it;
2. In your application's configuration file, enable the catalog entity relations graphic card extension so that the card begins to be presented on the catalog entity page:
```yaml
# app-config.yaml
app:
experimental:
# Auto discovering all plugins extensions
packages: all
extensions:
# This is required because the card is not enable by default once you install the plugin
- entity-card:catalog-graph/relations
```
```yaml
# app-config.yaml
app:
# Auto discovering all plugins extensions
packages: all
extensions:
# This is required because the card is not enable by default once you install the plugin
- entity-card:catalog-graph/relations
```
3. Then start the app, navigate to an entity's page and see the Relations graph there;
4. By clicking on the "View Graph" card action, you will be redirected to the catalog entity relations page.
## Customization
@@ -64,11 +64,10 @@ _Enabling auto discovering the plugin extensions in production_
# app-config.production.yaml
# Overriding configurations for the local production environment
app:
experimental:
packages:
# Only the following packages will be included
include:
- '@backstage/plugin-catalog-graph'
packages:
# Only the following packages will be included
include:
- '@backstage/plugin-catalog-graph'
```
_Disabling auto discovering the plugin extensions in development_
@@ -77,11 +76,10 @@ _Disabling auto discovering the plugin extensions in development_
# app-config.local.yaml
# Overriding configurations for the local development environment
app:
experimental:
packages:
# All but the following package will be included
exclude:
- '@backstage/plugin-catalog-graph'
packages:
# All but the following package will be included
exclude:
- '@backstage/plugin-catalog-graph'
```
For more options of package configurations, see [this](https://backstage.io/docs/frontend-system/architecture/app/#feature-discovery) documentation.
+2 -3
View File
@@ -48,9 +48,8 @@ And below is an example of how a user page looks with the user profile and owner
```yaml
# app-config.yaml
app:
experimental:
# Auto discovering all plugins extensions
packages: all
# Auto discovering all plugins extensions
packages: all
extensions:
# Enabling the org plugin cards
- entity-card:org/group-profile