From 729b188045846e3107afccf133d630c2febaecf2 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 29 Dec 2021 16:58:01 +0100 Subject: [PATCH] app-backend: update router to use static assets store and new cache headers Signed-off-by: Patrik Oldsberg --- .../app-backend/src/service/router.test.ts | 2 +- plugins/app-backend/src/service/router.ts | 48 +++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/plugins/app-backend/src/service/router.test.ts b/plugins/app-backend/src/service/router.test.ts index bbbf115834..30fa5454c0 100644 --- a/plugins/app-backend/src/service/router.test.ts +++ b/plugins/app-backend/src/service/router.test.ts @@ -81,7 +81,7 @@ describe('createRouter', () => { 'returns %s with default Cache-Control header', async file => { const response = await request(app).get(file); - expect(response.header['cache-control']).toBe('public, max-age=0'); + expect(response.header['cache-control']).toBe('public, max-age=1209600'); }, ); }); diff --git a/plugins/app-backend/src/service/router.ts b/plugins/app-backend/src/service/router.ts index 171684a964..cc476eab91 100644 --- a/plugins/app-backend/src/service/router.ts +++ b/plugins/app-backend/src/service/router.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { notFoundHandler, resolvePackagePath } from '@backstage/backend-common'; +import { + notFoundHandler, + PluginDatabaseManager, + resolvePackagePath, +} from '@backstage/backend-common'; import { Config } from '@backstage/config'; import helmet from 'helmet'; import express from 'express'; @@ -23,6 +27,15 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'path'; import { Logger } from 'winston'; import { injectConfig, readConfigs } from '../lib/config'; +import { + StaticAssetsStore, + findStaticAssets, + createStaticAssetsStoreMiddleware, +} from '../lib/assets'; +import { + CACHE_CONTROL_MAX_CACHE, + CACHE_CONTROL_NO_CACHE, +} from '../lib/headers'; // express uses mime v1 while we only have types for mime v2 type Mime = { lookup(arg0: string): string }; @@ -31,6 +44,12 @@ export interface RouterOptions { config: Config; logger: Logger; + /** + * The plugin database manager which of provided, the app-backend will use to cache previously + * deployed static assets. + */ + database?: PluginDatabaseManager; + /** * The name of the app package 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. @@ -94,7 +113,28 @@ export async function createRouter( // Use a separate router for static content so that a fallback can be provided by backend const staticRouter = Router(); - staticRouter.use(express.static(resolvePath(appDistDir, 'static'))); + staticRouter.use( + express.static(resolvePath(appDistDir, 'static'), { + setHeaders: res => { + res.setHeader('Cache-Control', CACHE_CONTROL_MAX_CACHE); + }, + }), + ); + + if (options.database) { + const store = await StaticAssetsStore.create({ + logger, + database: await options.database.getClient(), + }); + + const assets = await findStaticAssets(staticDir); + await store.storeAssets(assets); + // Remove any assets that are older than 7 days + await store.trimAssets({ maxAgeSeconds: 60 * 60 * 24 * 7 }); + + staticRouter.use(createStaticAssetsStoreMiddleware(store)); + } + if (staticFallbackHandler) { staticRouter.use(staticFallbackHandler); } @@ -109,7 +149,7 @@ export async function createRouter( if ( (express.static.mime as unknown as Mime).lookup(path) === 'text/html' ) { - res.setHeader('Cache-Control', 'no-store, max-age=0'); + res.setHeader('Cache-Control', CACHE_CONTROL_NO_CACHE); } }, }), @@ -119,7 +159,7 @@ export async function createRouter( headers: { // The Cache-Control header instructs the browser to not cache the index.html since it might // link to static assets from recently deployed versions. - 'cache-control': 'no-store, max-age=0', + 'cache-control': CACHE_CONTROL_NO_CACHE, }, }); });