diff --git a/packages/core-app-api/src/app/defaultConfigLoader.ts b/packages/core-app-api/src/app/defaultConfigLoader.ts index 00aee2d367..2ea8673f39 100644 --- a/packages/core-app-api/src/app/defaultConfigLoader.ts +++ b/packages/core-app-api/src/app/defaultConfigLoader.ts @@ -16,7 +16,6 @@ import { AppConfig } from '@backstage/config'; import { JsonObject } from '@backstage/types'; -import { AppConfigLoader } from './types'; /** * The default config loader, which expects that config is available at compile-time @@ -30,12 +29,17 @@ import { AppConfigLoader } from './types'; * * @public */ -export const defaultConfigLoader: AppConfigLoader = async ( +export async function defaultConfigLoader(): Promise { + return defaultConfigLoaderSync(); +} + +/** @internal */ +export function defaultConfigLoaderSync( // This string may be replaced at runtime to provide additional config. // It should be replaced by a JSON-serialized config object. // It's a param so we can test it, but at runtime this will always fall back to default. runtimeConfigJson: string = '__APP_INJECTED_RUNTIME_CONFIG__', -) => { +) { const appConfig = process.env.APP_CONFIG; if (!appConfig) { throw new Error('No static configuration provided'); @@ -70,4 +74,4 @@ export const defaultConfigLoader: AppConfigLoader = async ( }); } return configs; -}; +} diff --git a/packages/frontend-app-api/src/createApp.tsx b/packages/frontend-app-api/src/createApp.tsx index 41d16a7a9a..7393740863 100644 --- a/packages/frontend-app-api/src/createApp.tsx +++ b/packages/frontend-app-api/src/createApp.tsx @@ -35,6 +35,8 @@ import { RoutingProvider } from './routing/RoutingContext'; import { ApiHolder, appThemeApiRef, + ConfigApi, + configApiRef, RouteRef, } from '@backstage/core-plugin-api'; import { getAvailablePlugins } from './wiring/discovery'; @@ -44,16 +46,24 @@ import { ApiResolver, AppThemeSelector, } from '@backstage/core-app-api'; + +// TODO: Get rid of all of these // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppThemeProvider } from '../../core-app-api/src/app/AppThemeProvider'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { defaultConfigLoaderSync } from '../../core-app-api/src/app/defaultConfigLoader'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { themes } from '../../app-defaults/src/defaults/themes'; /** @public */ -export function createApp(options: { plugins: BackstagePlugin[] }): { +export function createApp(options: { + plugins: BackstagePlugin[]; + config?: ConfigApi; +}): { createRoot(): JSX.Element; } { - const appConfig = ConfigReader.fromConfigs(process.env.APP_CONFIG as any); + const appConfig = + options?.config ?? ConfigReader.fromConfigs(defaultConfigLoaderSync()); const builtinExtensions = [CoreRouter, Core]; const discoveredPlugins = getAvailablePlugins(); @@ -135,7 +145,7 @@ export function createApp(options: { plugins: BackstagePlugin[] }): { throw Error('Unable to find core extension instance'); } - const apiHolder = createApiHolder(coreInstance); + const apiHolder = createApiHolder(coreInstance, appConfig); return { createRoot() { @@ -162,7 +172,10 @@ export function createApp(options: { plugins: BackstagePlugin[] }): { }; } -function createApiHolder(coreExtension: ExtensionInstance): ApiHolder { +function createApiHolder( + coreExtension: ExtensionInstance, + configApi: ConfigApi, +): ApiHolder { const factoryRegistry = new ApiFactoryRegistry(); const apiFactories = @@ -187,6 +200,12 @@ function createApiHolder(coreExtension: ExtensionInstance): ApiHolder { factory: () => AppThemeSelector.createWithStorage(themes), }); + factoryRegistry.register('static', { + api: configApiRef, + deps: {}, + factory: () => configApi, + }); + ApiResolver.validateFactories(factoryRegistry, factoryRegistry.getAllApis()); return new ApiResolver(factoryRegistry);