This commit is contained in:
Andras Schmelczer 2026-07-03 18:01:10 +01:00
parent c2070693fb
commit 909e241907
55 changed files with 594 additions and 223 deletions

View file

@ -71,8 +71,8 @@ function getBrowserArgs(): string[] {
'--disable-gpu',
'--use-gl=swiftshader',
// Run the GPU (SwiftShader) work in the browser process to eliminate
// IPC overhead between browser and GPU processes significant win
// when all GL calls are CPU-bound anyway
// IPC overhead between browser and GPU processes (a significant win
// when all GL calls are CPU-bound anyway)
'--in-process-gpu',
];
}
@ -96,7 +96,7 @@ async function ensureContext(): Promise<BrowserContext> {
deviceScaleFactor: 1,
});
// Set up response caching at context level all pages share the cache.
// Set up response caching at context level: all pages share the cache.
// This means tiles fetched during pre-warm or a previous screenshot are
// served instantly for subsequent screenshots.
await sharedContext.route('**/*', async (route: Route) => {
@ -108,7 +108,7 @@ async function ensureContext(): Promise<BrowserContext> {
return;
}
// Cache hit fulfill from memory, zero network
// Cache hit: fulfill from memory, zero network
const cached = networkCache.get(url);
if (cached) {
await route.fulfill({
@ -119,7 +119,7 @@ async function ensureContext(): Promise<BrowserContext> {
return;
}
// Cache miss fetch, cache, fulfill
// Cache miss: fetch, cache, fulfill
try {
const response = await route.fetch();
const body = await response.body();
@ -190,7 +190,7 @@ async function releasePage(page: Page): Promise<void> {
/**
* Pre-warm the browser and populate the network cache by loading the app once.
* Subsequent screenshots benefit from cached JS/CSS bundles, map tiles,
* and V8 compiled bytecode eliminating cold-start latency.
* and V8 compiled bytecode, eliminating cold-start latency.
*
* Retries with exponential backoff if the frontend isn't up yet (common during
* docker-compose startup where the frontend may still be installing/building).
@ -214,7 +214,7 @@ export async function initialize(appUrl: string): Promise<void> {
timeout: READY_TIMEOUT,
});
} catch {
// Non-fatal cache will still have JS/CSS/tiles from the partial load
// Non-fatal: cache will still have JS/CSS/tiles from the partial load
}
console.log(`Pre-warm complete. Cache: ${networkCache.stats()}`);
await page.close().catch(() => { });
@ -256,7 +256,7 @@ export async function takeScreenshot(url: string, authHeader?: string): Promise<
// Inject Authorization header on API requests so the headless browser
// is authenticated (required for licensed users outside the free zone).
// Page-level routes take precedence over the context-level cache route,
// so only /api/ requests are affected — static assets still use the cache.
// so only /api/ requests are affected. Static assets still use the cache.
if (authHeader) {
await page.route('**/api/**', async (route) => {
const headers = { ...route.request().headers(), authorization: authHeader };
@ -297,7 +297,7 @@ export async function takeScreenshot(url: string, authHeader?: string): Promise<
// Buffer for SwiftShader to finish rendering the WebGL frame after
// __screenshot_ready fires. The frontend uses double-rAF before signaling,
// so one paint cycle has already completed — this is extra safety for
// so one paint cycle has already completed. This is extra safety for
// compositor staging and any residual tile/layer rendering.
await page.waitForTimeout(RENDER_BUFFER_MS);