Merge pull request #4836 from SDA-SE/feat/no-cache-app-router
Add a `Cache-Control: no-store` header to the `index.html` response to instruct the browser to not cache the pages
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-app-backend': patch
|
||||
---
|
||||
|
||||
Add a `Cache-Control: no-store, max-age=0` header to the `index.html` response to instruct the browser to not cache the pages.
|
||||
This tells the browser to not serve a cached `index.html` that might link to static assets from a previous deployment that are not available anymore.
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import request from 'supertest';
|
||||
import { createRouter } from './router';
|
||||
|
||||
@@ -68,6 +68,22 @@ describe('createRouter', () => {
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.text.trim()).toBe('this is index.html');
|
||||
});
|
||||
|
||||
it.each(['/index.html', '/other.html', '/missing.html'])(
|
||||
'returns %s with no-store Cache-Control header',
|
||||
async file => {
|
||||
const response = await request(app).get(file);
|
||||
expect(response.header['cache-control']).toBe('no-store, max-age=0');
|
||||
},
|
||||
);
|
||||
|
||||
it.each(['/static/main.txt'])(
|
||||
'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');
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('createRouter with static fallback handler', () => {
|
||||
|
||||
@@ -14,14 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { Logger } from 'winston';
|
||||
import { notFoundHandler, resolvePackagePath } from '@backstage/backend-common';
|
||||
import { Config } from '@backstage/config';
|
||||
import { injectConfig, readConfigs } from '../lib/config';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import fs from 'fs-extra';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { Logger } from 'winston';
|
||||
import { injectConfig, readConfigs } from '../lib/config';
|
||||
|
||||
// express uses mime v1 while we only have types for mime v2
|
||||
type Mime = { lookup(arg0: string): string };
|
||||
|
||||
export interface RouterOptions {
|
||||
config: Config;
|
||||
@@ -95,9 +98,28 @@ export async function createRouter(
|
||||
staticRouter.use(notFoundHandler());
|
||||
|
||||
router.use('/static', staticRouter);
|
||||
router.use(express.static(appDistDir));
|
||||
router.use(
|
||||
express.static(appDistDir, {
|
||||
setHeaders: (res, path) => {
|
||||
// The Cache-Control header instructs the browser to not cache html files since it might
|
||||
// link to static assets from recently deployed versions.
|
||||
if (
|
||||
((express.static.mime as unknown) as Mime).lookup(path) ===
|
||||
'text/html'
|
||||
) {
|
||||
res.setHeader('Cache-Control', 'no-store, max-age=0');
|
||||
}
|
||||
},
|
||||
}),
|
||||
);
|
||||
router.get('/*', (_req, res) => {
|
||||
res.sendFile(resolvePath(appDistDir, 'index.html'));
|
||||
res.sendFile(resolvePath(appDistDir, 'index.html'), {
|
||||
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',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return router;
|
||||
|
||||
Reference in New Issue
Block a user