Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit 8cc94db

Browse files
committed
Improve server Etag logic
1 parent c2222af commit 8cc94db

File tree

3 files changed

+32
-25
lines changed

3 files changed

+32
-25
lines changed

server/mod.ts

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -102,17 +102,22 @@ export const serve = (options: ServerOptions = {}) => {
102102
stat = await Deno.lstat(filePath);
103103
}
104104
if (stat.isFile) {
105-
const { mtime } = stat;
106-
const etag = mtime ? mtime.getTime().toString(16) + "-" + stat.size.toString(16) : null;
105+
const headers = new Headers({ "Content-Type": contentType });
106+
const deployId = Deno.env.get("DENO_DEPLOYMENT_ID");
107+
let etag: string | null = null;
108+
if (deployId) {
109+
etag = `${btoa(pathname).replace(/[^a-z0-9]/g, "")}-${deployId}`;
110+
} else {
111+
const { mtime, size } = stat;
112+
if (mtime) {
113+
etag = mtime.getTime().toString(16) + "-" + size.toString(16);
114+
headers.append("Last-Modified", new Date(mtime).toUTCString());
115+
}
116+
}
107117
if (etag && req.headers.get("If-None-Match") === etag) {
108118
return new Response(null, { status: 304 });
109119
}
110120
const file = await Deno.open(filePath, { read: true });
111-
const headers = new Headers({ "Content-Type": contentType });
112-
if (mtime) {
113-
headers.set("Etag", etag!);
114-
headers.set("Last-Modified", mtime.toUTCString());
115-
}
116121
return new Response(readableStreamFromReader(file), { headers });
117122
}
118123
} catch (err) {
@@ -134,30 +139,31 @@ export const serve = (options: ServerOptions = {}) => {
134139
}
135140
}
136141

137-
let cookies: Map<string, string> | null = null;
138-
139142
const customHTMLRewriter = new Map<string, HTMLRewriterHandlers>();
140143
const ctx = {
141144
params: {},
142145
headers: new Headers(),
143146
cookies: {
144-
get: (name: string) => {
145-
if (cookies === null) {
146-
cookies = new Map<string, string>();
147+
_cookies: null as Map<string, string> | null,
148+
get(name: string) {
149+
if (this._cookies === null) {
150+
this._cookies = new Map<string, string>();
147151
const cookieHeader = req.headers.get("Cookie");
148152
if (cookieHeader) {
149153
for (const cookie of cookieHeader.split(";")) {
150154
const [key, value] = util.splitBy(cookie, "=");
151-
cookies.set(key.trim(), value);
155+
this._cookies.set(key.trim(), value);
152156
}
153157
}
154158
}
155-
return cookies.get(name);
159+
return this._cookies.get(name);
156160
},
157-
set: (name: string, value: string, options?: CookieOptions) => {
161+
set(name: string, value: string, options?: CookieOptions) {
162+
this._cookies?.set(name, value);
158163
ctx.headers.set("Set-Cookie", setCookieHeader(name, value, options));
159164
},
160-
delete: (name: string, options?: CookieOptions) => {
165+
delete(name: string, options?: CookieOptions) {
166+
this._cookies?.delete(name);
161167
ctx.headers.set("Set-Cookie", setCookieHeader(name, "", { ...options, expires: new Date(0) }));
162168
},
163169
},
@@ -321,12 +327,13 @@ export const serve = (options: ServerOptions = {}) => {
321327
log.setLevel(logLevel);
322328
}
323329

330+
// clean global cached objects
331+
Reflect.deleteProperty(globalThis, "__UNO_GENERATOR");
332+
Reflect.deleteProperty(globalThis, "__ALEPH_INDEX_HTML");
333+
324334
// inject global `__ALEPH_CONFIG`
325335
Reflect.set(globalThis, "__ALEPH_CONFIG", Object.assign({}, config));
326336

327-
// delete previous `__UNO_GENERATOR`
328-
Reflect.deleteProperty(globalThis, "__UNO_GENERATOR");
329-
330337
const { hostname, port = 8080, certFile, keyFile, signal } = options;
331338
if (Deno.env.get("ALEPH_CLI")) {
332339
Reflect.set(globalThis, "__ALEPH_SERVER", { hostname, port, certFile, keyFile, handler, signal });

server/serve_dist.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ export default {
2525
ctype = "text/css; charset=utf-8";
2626
}
2727
const headers = new Headers({ "Content-Type": ctype });
28-
const deplyId = Deno.env.get("DENO_DEPLOYMENT_ID");
28+
const deployId = Deno.env.get("DENO_DEPLOYMENT_ID");
2929
let etag: string | null = null;
30-
if (deplyId) {
31-
etag = `${btoa(pathname).replace(/[^a-z0-9]/g, "")}-${deplyId}`;
30+
if (deployId) {
31+
etag = `${btoa(pathname).replace(/[^a-z0-9]/g, "")}-${deployId}`;
3232
} else {
3333
const stat = await Deno.lstat(filePath);
3434
if (!stat.isFile) {

server/transformer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default {
3030
const { isDev, buildHash, loaded } = options;
3131
const { pathname, searchParams, search } = new URL(req.url);
3232
const specifier = pathname.startsWith("/-/") ? restoreUrl(pathname + search) : `.${pathname}`;
33+
3334
let sourceCode: string;
3435
let mtime: number | undefined;
3536
let lang: string | undefined;
@@ -47,10 +48,9 @@ export default {
4748
isCSS = codeType.startsWith("text/css");
4849
uno = pathname.endsWith(".jsx") || pathname.endsWith(".tsx");
4950
}
51+
5052
const etag = mtime
51-
? `${mtime.toString(16)}-${sourceCode.length.toString(16)}-${
52-
sourceCode.charCodeAt(Math.floor(sourceCode.length / 2)).toString(16)
53-
}${buildHash.slice(0, 8)}`
53+
? `${mtime.toString(16)}-${sourceCode.length.toString(16)}-${buildHash.slice(0, 8)}`
5454
: await util.computeHash("sha-1", sourceCode + buildHash);
5555
if (req.headers.get("If-None-Match") === etag) {
5656
return new Response(null, { status: 304 });

0 commit comments

Comments
 (0)