Skip to content

Commit

Permalink
perf(ssr): Etag SSR HTML output for proper CDN cache
Browse files Browse the repository at this point in the history
  • Loading branch information
leomp12 committed Oct 23, 2024
1 parent 6231f2d commit d58472a
Showing 1 changed file with 25 additions and 5 deletions.
30 changes: 25 additions & 5 deletions packages/ssr/src/lib/serve-storefront.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Request, Response } from 'firebase-functions';
import type { GroupedAnalyticsEvents } from './analytics/send-analytics-events';
import { join as joinPath } from 'node:path';
import { readFile } from 'node:fs/promises';
import { createHash } from 'node:crypto';
import config, { logger } from '@cloudcommerce/firebase/lib/config';
import { checkUserAgent, fetchAndCache } from './util/ssr-utils';
import { sendAnalyticsEvents } from './analytics/send-analytics-events';
Expand Down Expand Up @@ -198,14 +199,26 @@ export default async (req: Request, res: Response) => {
*/
/* eslint-disable prefer-rest-params */
const startedAt = Date.now();
let resolveHeaders: ((v: [number, OutgoingHttpHeaders]) => any) | undefined;
const waitingHeaders = new Promise<[number, OutgoingHttpHeaders]>((resolve) => {
resolveHeaders = resolve;
});
let resolveHeadersSent: ((v: any) => any) | undefined;
const waitingHeadersSent = new Promise((resolve) => {
resolveHeadersSent = resolve;
});
const writes: Promise<any>[] = [];
let outputHtml: string = '';
const _write = res.write;
// @ts-ignore
res.write = function write(...args: any) {
res.write = function write(...args: [string | Buffer | Uint8Array, any]) {
const [chunk] = args;
try {
const html = chunk.toString();
if (html) outputHtml += html;
} catch {
//
}
writes.push(new Promise((resolve) => {
waitingHeadersSent.finally(() => {
if (!res.writableEnded) _write.apply(res, args);
Expand All @@ -214,10 +227,18 @@ export default async (req: Request, res: Response) => {
}));
};
let sid: string | undefined;
const _writeHead = res.writeHead;
const _end = res.end;
// @ts-ignore
res.end = async function end(...args: any) {
await waitingHeadersSent;
if (!res.headersSent) {
const [status, headers] = await waitingHeaders;
if (status === 200 && outputHtml) {
headers.etag = createHash('sha256').update(outputHtml).digest('base64');
}
_writeHead.apply(res, [status, headers]);
}
resolveHeadersSent?.(null);
setTimeout(async () => {
await Promise.all(writes);
if (!res.writableEnded) _end.apply(res, args);
Expand All @@ -230,7 +251,6 @@ export default async (req: Request, res: Response) => {
}, 1);
};

const _writeHead = res.writeHead;
// @ts-ignore
res.writeHead = async function writeHead(status: number, headers?: OutgoingHttpHeaders) {
if (!headers) {
Expand Down Expand Up @@ -276,8 +296,7 @@ export default async (req: Request, res: Response) => {
delete headers['CDN-Tag'];
}
headers['X-Async-Ex'] = `${execId}_${Date.now() - startedAt}`;
_writeHead.apply(res, [status, headers]);
resolveHeadersSent?.(null);
resolveHeaders?.([status, headers]);
};

const setStatusAndCache = (status: number, cacheControl: string) => {
Expand All @@ -301,6 +320,7 @@ export default async (req: Request, res: Response) => {
.send(err.toString());
}
resolveHeadersSent?.(null);
resolveHeaders?.([status, res.getHeaders()]);
};

const handleException = (err: Error) => {
Expand Down

0 comments on commit d58472a

Please sign in to comment.