feat(seo): add compression, cache-control headers, configurable frontend dist path

This commit is contained in:
2026-08-02 10:20:22 +02:00
parent 26433fa9c7
commit 5ff8a865e8
5 changed files with 160 additions and 2 deletions
+59
View File
@@ -0,0 +1,59 @@
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import request from 'supertest';
import fs from 'node:fs/promises';
import path from 'node:path';
import os from 'node:os';
import { createApp } from '../src/app.js';
import { getPrismaClient, closePrismaClient } from '../src/db.js';
import { loadConfig } from '../src/config.js';
import { ensureStorageDirs } from '../src/storage.js';
let app;
let prisma;
let config;
let frontendDist;
beforeAll(async () => {
frontendDist = await fs.mkdtemp(path.join(os.tmpdir(), 'converter-dist-'));
await fs.mkdir(path.join(frontendDist, 'fr'), { recursive: true });
await fs.mkdir(path.join(frontendDist, 'assets'), { recursive: true });
await fs.writeFile(
path.join(frontendDist, 'fr', 'index.html'),
`<html><body>fr home ${'x'.repeat(2000)}</body></html>`
);
await fs.writeFile(path.join(frontendDist, 'assets', 'app.abc123.js'), 'console.log(1)');
config = {
...loadConfig(),
storageDir: await fs.mkdtemp(path.join(os.tmpdir(), 'converter-api-')),
frontendDist,
};
await ensureStorageDirs(config);
prisma = getPrismaClient(config);
app = createApp(config, prisma);
});
afterAll(async () => {
await closePrismaClient();
await fs.rm(config.storageDir, { recursive: true, force: true });
await fs.rm(frontendDist, { recursive: true, force: true });
});
describe('static asset serving', () => {
it('sends HTML pages with Cache-Control: no-cache', async () => {
const response = await request(app).get('/fr/');
expect(response.status).toBe(200);
expect(response.headers['cache-control']).toBe('no-cache');
});
it('sends hashed assets with a long immutable Cache-Control', async () => {
const response = await request(app).get('/assets/app.abc123.js');
expect(response.status).toBe(200);
expect(response.headers['cache-control']).toBe('public, max-age=31536000, immutable');
});
it('compresses responses when the client accepts it', async () => {
const response = await request(app).get('/fr/').set('Accept-Encoding', 'gzip');
expect(response.headers['content-encoding']).toBe('gzip');
});
});