Caddy가 commit-digest 공용 asset과 sourcemap을 immutable URL로 제공하고, runtime에 공용 공개 경로를 명시한다.
77 lines
3.0 KiB
JavaScript
77 lines
3.0 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs/promises';
|
|
|
|
test('Caddy caches only content-hashed Vite frontend assets as immutable', async () => {
|
|
const caddyfile = await fs.readFile(new URL('../caddy/Caddyfile', import.meta.url), 'utf8');
|
|
const matcher = caddyfile.match(
|
|
/@immutableFrontendAssets path_regexp immutableFrontendAssets (\S+)/,
|
|
);
|
|
|
|
assert.ok(matcher, 'immutable frontend asset matcher must exist');
|
|
const assetPath = new RegExp(matcher[1]);
|
|
|
|
for (const profile of ['gateway', 'che', 'kwe', 'pwe', 'twe', 'nya', 'pya', 'hwe']) {
|
|
assert.equal(assetPath.test(`/${profile}/assets/index-CcXtLSVk.js`), true);
|
|
assert.equal(assetPath.test(`/${profile}/assets/index-CcXtLSVk.js.map`), true);
|
|
}
|
|
|
|
assert.equal(assetPath.test('/gateway/'), false);
|
|
assert.equal(assetPath.test('/gateway/terms.1.html'), false);
|
|
assert.equal(assetPath.test('/gateway/assets/index.js'), false);
|
|
assert.equal(assetPath.test('/image/game/figure.png'), false);
|
|
assert.match(
|
|
caddyfile,
|
|
/header @immutableFrontendAssets >Cache-Control "public, max-age=31536000, immutable"/,
|
|
);
|
|
|
|
const sharedMatcher = caddyfile.match(
|
|
/@immutableSharedProfileAssets path_regexp immutableSharedProfileAssets (\S+)/,
|
|
);
|
|
assert.ok(sharedMatcher, 'immutable shared profile asset matcher must exist');
|
|
const sharedAssetPath = new RegExp(sharedMatcher[1]);
|
|
const releaseId = `${'a'.repeat(40)}-${'b'.repeat(16)}`;
|
|
assert.equal(
|
|
sharedAssetPath.test(`/gateway/profile-assets/${releaseId}/assets/index-CcXtLSVk.js`),
|
|
true,
|
|
);
|
|
assert.equal(
|
|
sharedAssetPath.test(`/gateway/profile-assets/${releaseId}/assets/index-CcXtLSVk.js.map`),
|
|
true,
|
|
);
|
|
assert.equal(sharedAssetPath.test(`/gateway/profile-assets/${releaseId}/index.html`), false);
|
|
assert.match(
|
|
caddyfile,
|
|
/header @immutableSharedProfileAssets >Cache-Control "public, max-age=31536000, immutable"/,
|
|
);
|
|
});
|
|
|
|
test('Caddy serves published frontend artifacts directly and keeps a transition fallback', async () => {
|
|
const caddyfile = await fs.readFile(new URL('../caddy/Caddyfile', import.meta.url), 'utf8');
|
|
for (const [profile, port] of Object.entries({
|
|
gateway: 15000,
|
|
che: 15002,
|
|
kwe: 15004,
|
|
pwe: 15006,
|
|
twe: 15008,
|
|
nya: 15010,
|
|
pya: 15012,
|
|
hwe: 15014,
|
|
})) {
|
|
assert.match(caddyfile, new RegExp(`/srv/frontend-artifacts/${profile}/current`));
|
|
assert.match(caddyfile, new RegExp(`reverse_proxy runtime:${port}`));
|
|
assert.match(
|
|
caddyfile,
|
|
new RegExp(`route \\{[\\s\\S]*?@${profile}Asset path /assets/\\*[\\s\\S]*?handle @${profile}Asset`),
|
|
);
|
|
}
|
|
assert.match(caddyfile, /try_files \{path\} \/index\.html/);
|
|
assert.match(caddyfile, /header @frontendRequests Cache-Control "no-cache"/);
|
|
assert.match(
|
|
caddyfile,
|
|
/@sharedProfileAsset path_regexp sharedProfileAsset \^\/gateway\/profile-assets\//,
|
|
);
|
|
assert.match(caddyfile, /root \* \/srv\/frontend-artifacts\/game-assets\/releases/);
|
|
assert.match(caddyfile, /uri strip_prefix \/gateway\/profile-assets/);
|
|
});
|