From d564ad142b1737b22643d6e5829f6752ae07f001 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Aug 2023 15:30:49 +0200 Subject: [PATCH] app-backend: migrate to use static configuration and extension point Signed-off-by: Patrik Oldsberg --- .changeset/sharp-months-think.md | 5 ++ plugins/app-backend/alpha-api-report.md | 11 +-- plugins/app-backend/config.d.ts | 46 +++++++++++ plugins/app-backend/package.json | 3 + plugins/app-backend/src/alpha.ts | 1 - .../app-backend/src/service/appPlugin.test.ts | 14 ++-- plugins/app-backend/src/service/appPlugin.ts | 79 ++++++------------- yarn.lock | 3 +- 8 files changed, 92 insertions(+), 70 deletions(-) create mode 100644 .changeset/sharp-months-think.md create mode 100644 plugins/app-backend/config.d.ts diff --git a/.changeset/sharp-months-think.md b/.changeset/sharp-months-think.md new file mode 100644 index 0000000000..04ffbb8d1b --- /dev/null +++ b/.changeset/sharp-months-think.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-app-backend': patch +--- + +Migrated the alpha `appBackend` export to use static configuration and extension points rather than accepting options. diff --git a/plugins/app-backend/alpha-api-report.md b/plugins/app-backend/alpha-api-report.md index 20a2902557..5fb0546a79 100644 --- a/plugins/app-backend/alpha-api-report.md +++ b/plugins/app-backend/alpha-api-report.md @@ -4,18 +4,9 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; -import express from 'express'; // @alpha -export const appPlugin: (options: AppPluginOptions) => BackendFeature; - -// @alpha (undocumented) -export type AppPluginOptions = { - appPackageName?: string; - staticFallbackHandler?: express.Handler; - disableConfigInjection?: boolean; - disableStaticFallbackCache?: boolean; -}; +export const appPlugin: () => BackendFeature; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/app-backend/config.d.ts b/plugins/app-backend/config.d.ts new file mode 100644 index 0000000000..dc11bc4e0a --- /dev/null +++ b/plugins/app-backend/config.d.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2023 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 interface Config { + app?: { + /** + * The name of the app package (in most Backstage repositories, this is the + * "name" field in `packages/app/package.json`) that content should be served + * from. The same app package should be added as a dependency to the backend + * package in order for it to be accessible at runtime. + * + * In a typical setup with a single app package, this will default to 'app'. + */ + packageName?: string; + + /** + * Disables the configuration injection. This can be useful if you're running in an environment + * with a read-only filesystem, or for some other reason don't want configuration to be injected. + * + * Note that this will cause the configuration used when building the app bundle to be used, unless + * a separate configuration loading strategy is set up. + * + * This also disables configuration injection though `APP_CONFIG_` environment variables. + */ + disableConfigInjection?: boolean; + + /** + * By default the app backend plugin will cache previously deployed static assets in the database. + * If you disable this, it is recommended to set a `staticFallbackHandler` instead. + */ + disableStaticFallbackCache?: boolean; + }; +} diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index c9b25508c0..be1b6b3a80 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -49,6 +49,7 @@ "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/config-loader": "workspace:^", + "@backstage/plugin-app-node": "workspace:^", "@backstage/types": "workspace:^", "@types/express": "^4.17.6", "express": "^4.17.1", @@ -73,8 +74,10 @@ "node-fetch": "^2.6.7", "supertest": "^6.1.3" }, + "configSchema": "config.d.ts", "files": [ "dist", + "config.d.ts", "migrations/**/*.{js,d.ts}", "static" ] diff --git a/plugins/app-backend/src/alpha.ts b/plugins/app-backend/src/alpha.ts index cc8276b853..edb5c8caf5 100644 --- a/plugins/app-backend/src/alpha.ts +++ b/plugins/app-backend/src/alpha.ts @@ -15,4 +15,3 @@ */ export { appPlugin } from './service/appPlugin'; -export type { AppPluginOptions } from './service/appPlugin'; diff --git a/plugins/app-backend/src/service/appPlugin.test.ts b/plugins/app-backend/src/service/appPlugin.test.ts index 518f56b7f9..37d38663ef 100644 --- a/plugins/app-backend/src/service/appPlugin.test.ts +++ b/plugins/app-backend/src/service/appPlugin.test.ts @@ -17,7 +17,7 @@ import mockFs from 'mock-fs'; import { resolve as resolvePath } from 'path'; import fetch from 'node-fetch'; -import { startTestBackend } from '@backstage/backend-test-utils'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { appPlugin } from './appPlugin'; describe('appPlugin', () => { @@ -39,10 +39,14 @@ describe('appPlugin', () => { it('boots', async () => { const { server } = await startTestBackend({ - features: [ - appPlugin({ - appPackageName: 'app', - disableStaticFallbackCache: true, + features: [appPlugin()], + services: [ + mockServices.rootConfig.factory({ + data: { + app: { + disableStaticFallbackCache: true, + }, + }, }), ], }); diff --git a/plugins/app-backend/src/service/appPlugin.ts b/plugins/app-backend/src/service/appPlugin.ts index a223d3ffb5..7f521acfb9 100644 --- a/plugins/app-backend/src/service/appPlugin.ts +++ b/plugins/app-backend/src/service/appPlugin.ts @@ -21,58 +21,28 @@ import { } from '@backstage/backend-plugin-api'; import { createRouter } from './router'; import { loggerToWinstonLogger } from '@backstage/backend-common'; - -/** @alpha */ -export type AppPluginOptions = { - /** - * The name of the app package (in most Backstage repositories, this is the - * "name" field in `packages/app/package.json`) that content should be served - * from. The same app package should be added as a dependency to the backend - * package in order for it to be accessible at runtime. - * - * In a typical setup with a single app package, this will default to 'app'. - */ - appPackageName?: string; - - /** - * A request handler to handle requests for static content that are not present in the app bundle. - * - * This can be used to avoid issues with clients on older deployment versions trying to access lazy - * loaded content that is no longer present. Typically the requests would fall back to a long-term - * object store where all recently deployed versions of the app are present. - * - * Another option is to provide a `database` that will take care of storing the static assets instead. - * - * If both `database` and `staticFallbackHandler` are provided, the `database` will attempt to serve - * static assets first, and if they are not found, the `staticFallbackHandler` will be called. - */ - staticFallbackHandler?: express.Handler; - - /** - * Disables the configuration injection. This can be useful if you're running in an environment - * with a read-only filesystem, or for some other reason don't want configuration to be injected. - * - * Note that this will cause the configuration used when building the app bundle to be used, unless - * a separate configuration loading strategy is set up. - * - * This also disables configuration injection though `APP_CONFIG_` environment variables. - */ - disableConfigInjection?: boolean; - - /** - * By default the app backend plugin will cache previously deployed static assets in the database. - * If you disable this, it is recommended to set a `staticFallbackHandler` instead. - */ - disableStaticFallbackCache?: boolean; -}; +import { staticFallbackHandlerExtensionPoint } from '@backstage/plugin-app-node'; /** * The App plugin is responsible for serving the frontend app bundle and static assets. * @alpha */ -export const appPlugin = createBackendPlugin((options: AppPluginOptions) => ({ +export const appPlugin = createBackendPlugin({ pluginId: 'app', register(env) { + let staticFallbackHandler: express.Handler | undefined; + + env.registerExtensionPoint(staticFallbackHandlerExtensionPoint, { + setStaticFallbackHandler(handler) { + if (staticFallbackHandler) { + throw new Error( + 'Attempted to install a static fallback handler for the app-backend twice', + ); + } + staticFallbackHandler = handler; + }, + }); + env.registerInit({ deps: { logger: coreServices.logger, @@ -81,19 +51,22 @@ export const appPlugin = createBackendPlugin((options: AppPluginOptions) => ({ httpRouter: coreServices.httpRouter, }, async init({ logger, config, database, httpRouter }) { - const { - appPackageName, - staticFallbackHandler, - disableConfigInjection, - disableStaticFallbackCache, - } = options; + const appPackageName = + config.getOptionalString('app.packageName') ?? 'app'; + const disableConfigInjection = config.getOptionalBoolean( + 'app.disableConfigInjection', + ); + const disableStaticFallbackCache = config.getOptionalBoolean( + 'app.disableStaticFallbackCache', + ); + const winstonLogger = loggerToWinstonLogger(logger); const router = await createRouter({ logger: winstonLogger, config, database: disableStaticFallbackCache ? undefined : database, - appPackageName: appPackageName ?? 'app', + appPackageName, staticFallbackHandler, disableConfigInjection, }); @@ -101,4 +74,4 @@ export const appPlugin = createBackendPlugin((options: AppPluginOptions) => ({ }, }); }, -})); +}); diff --git a/yarn.lock b/yarn.lock index d18e8fbc66..2ed762bf99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4637,6 +4637,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/config-loader": "workspace:^" + "@backstage/plugin-app-node": "workspace:^" "@backstage/types": "workspace:^" "@types/express": ^4.17.6 "@types/supertest": ^2.0.8 @@ -25462,7 +25463,7 @@ __metadata: languageName: node linkType: hard -"express@npm:^4.17.1, express@npm:^4.17.3, express@npm:^4.18.1": +"express@npm:^4.17.1, express@npm:^4.17.3, express@npm:^4.18.1, express@npm:^4.18.2": version: 4.18.2 resolution: "express@npm:4.18.2" dependencies: