mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-17 04:35:50 +00:00
fix(kimi-web): cache content-hashed assets (#2865)
This commit is contained in:
parent
cb30a7799d
commit
53909d91e3
3 changed files with 69 additions and 1 deletions
5
.changeset/cache-web-assets.md
Normal file
5
.changeset/cache-web-assets.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@moonshot-ai/kimi-code": patch
|
||||
---
|
||||
|
||||
Cache content-hashed Kimi Web assets across reloads while keeping the app entry point revalidated.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { createReadStream } from 'node:fs';
|
||||
import { stat } from 'node:fs/promises';
|
||||
import { extname, join, normalize, resolve, sep } from 'node:path';
|
||||
import { extname, join, normalize, relative, resolve, sep } from 'node:path';
|
||||
|
||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||
|
||||
|
|
@ -56,10 +56,20 @@ async function serveWebAsset(
|
|||
|
||||
return reply
|
||||
.type(mimeType(filePath))
|
||||
.header('Cache-Control', cacheControl(assetsDir, filePath))
|
||||
.header('Content-Length', String(fileInfo.size))
|
||||
.send(createReadStream(filePath));
|
||||
}
|
||||
|
||||
function cacheControl(assetsDir: string, filePath: string): string {
|
||||
const assetPath = relative(assetsDir, filePath);
|
||||
const fileName = filePath.slice(filePath.lastIndexOf(sep) + 1);
|
||||
if (assetPath.startsWith(`assets${sep}`) && /[-.][A-Za-z0-9_-]{8}\.[^.]+$/.test(fileName)) {
|
||||
return 'public, max-age=31536000, immutable';
|
||||
}
|
||||
return 'no-cache';
|
||||
}
|
||||
|
||||
async function resolveStaticFile(
|
||||
assetsDir: string,
|
||||
pathname: string,
|
||||
|
|
|
|||
53
packages/kap-server/test/webAssets.test.ts
Normal file
53
packages/kap-server/test/webAssets.test.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import Fastify, { type FastifyInstance } from 'fastify';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
|
||||
import { registerWebAssetRoutes } from '../src/routes/webAssets';
|
||||
|
||||
describe('web asset cache policy', () => {
|
||||
let app: FastifyInstance;
|
||||
let assetsDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
assetsDir = await mkdtemp(join(tmpdir(), 'kimi-web-assets-'));
|
||||
await mkdir(join(assetsDir, 'assets'));
|
||||
await Promise.all([
|
||||
writeFile(join(assetsDir, 'index.html'), '<main>Kimi</main>'),
|
||||
writeFile(join(assetsDir, 'assets', 'index-Dy7xs5tu.js'), 'export {};'),
|
||||
writeFile(join(assetsDir, 'assets', 'application-configuration.json'), '{}'),
|
||||
writeFile(join(assetsDir, 'favicon.svg'), '<svg></svg>'),
|
||||
]);
|
||||
app = Fastify();
|
||||
await registerWebAssetRoutes(app, assetsDir);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
await rm(assetsDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('caches content-hashed assets as immutable', async () => {
|
||||
const response = await app.inject({ method: 'GET', url: '/assets/index-Dy7xs5tu.js' });
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.headers['cache-control']).toBe('public, max-age=31536000, immutable');
|
||||
});
|
||||
|
||||
it.each([
|
||||
'/index.html',
|
||||
'/sessions/active',
|
||||
'/favicon.svg',
|
||||
'/assets/application-configuration.json',
|
||||
])(
|
||||
'requires revalidation for %s',
|
||||
async (url) => {
|
||||
const response = await app.inject({ method: 'GET', url });
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.headers['cache-control']).toBe('no-cache');
|
||||
},
|
||||
);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue