From dda29180f055a7fbcef24db5a8f254bf2ff44f8a Mon Sep 17 00:00:00 2001 From: codehz Date: Fri, 5 Jul 2024 18:08:15 +0800 Subject: [PATCH] add hash to entrypoint --- build.ts | 16 ++++++++++++++-- bun.lockb | Bin 14996 -> 14354 bytes example/index.ts | 6 +++++- index.tsx | 22 ++++++++++++++++------ package.json | 4 ++-- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/build.ts b/build.ts index 9fda71e..a283f8d 100644 --- a/build.ts +++ b/build.ts @@ -1,6 +1,6 @@ import { Glob, fileURLToPath, pathToFileURL } from "bun"; import { unlink } from "node:fs/promises"; -import { basename, join } from "node:path"; +import { basename, join, relative } from "node:path"; function escapeRegExp(string: string) { return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string @@ -38,11 +38,12 @@ export async function build({ for await (const path of glob(absPageDir)) { entrypoints.push(path); } + const outdir = join(baseDir, buildDir); const result = await Bun.build({ entrypoints, sourcemap, target: "browser", - outdir: join(baseDir, buildDir), + outdir, splitting: true, minify, define: { @@ -99,6 +100,17 @@ export async function build({ await unlink(path); } } + const hashed: Record = {}; + for (const output of result.outputs) { + if (output.kind === "entry-point" && output.hash) { + const path = relative(outdir, output.path); + hashed[`/${path}`] = output.hash; + } + } + Bun.write( + join(outdir, ".meta.json"), + JSON.stringify({ version: 1, hashed }) + ); } return result; } diff --git a/bun.lockb b/bun.lockb index 8680085cb421642a7c1352678fe58b80a8145a7c..c4ff1c081af356888b0c61566067b53b6c3b0f58 100755 GIT binary patch delta 1142 zcmbPII;miSp5}84jR%ZAPdBeWBEDelva`>gv^G6hv{_#J^3UGqug*2iZ8B#71J#M) z@=SuN8!I#znGCo#Z(>wq-28%R0*A&yP6mb`28IS z1d^I8%OAnWIJt~J97vu6lWGDWb{&|!1}60cK_YEn@*bEp69S3!fyrlJ(oPs8G7U_= z1CwqdAdz`s@*9}+69tJZ1C#&2WSAI8WF44f69=*5z~nYC$tM94NduGnz@(TYNF)zT z9s`qdQXr8sFnLZ&yng9wP5zqG8a{9aDJ(n=}?2Hl5(A%qzHyPm*zRq3o&60kRxSn;Yac*|{QAA&zWN zoh+(uZ@|Ft?>_{9gh3tv`hx+O^uPed-vHI*pf=e{Lv8X3brnXf$rsg?C;w3QP zR|k|^Wxn~A-bGHaqGa9VWW&^CGlLX^6kQ_&BNGEN1M|s>Ceo9SS%@cF>KW)6=wer- zSCU?3pl4)?Q$cZZMrulFPHK@MK4ZXkiCOZ?;8nEIM1JxeOG!E0wt<{8d7{h=0IR)2 Ax&QzG delta 1464 zcmbPKFr{>Yp612)*M$jsPMspBP3z4gJ!)PoG0YYHRHNwLKQ-clyG;m-6$2QkPYjo5 z;#S{Sp}{EhjFW+Zhk>D?j*Ec-$ZYt;xp@(z8lwQy^}>efjz-!qR&?=SyT(?q`2^Dh z4&K#3CDuSyLO^qvCSPRIo;-n>lLshhj3Ow&%)zS%G|&Mk$_P}-0#*tX?5d8#nC0cjT3OCfdPEO(C@Ybk3vaWn1qYqfhH zQqtsiar=y%AMWOzR#`JRx2fN$U!WcQb-SU}G{$WczD-cJ^4#;_f!ex_`R6r}3|2!n znCtfBwhVSNzR!wN8{%{iY*sR6uKaOa?v}a62kunQsh79u9CdC9+V{G~ZPmJ_4HJK? zHPC(i+0MLiVVc4Xd-=FvB(s3b$^0^VH$RZ(V45tz%)$rDSjjn=dRfJj6{Vv#>&QK2 zn`|JR#1)_p(OIEBSz6Uz@85q2011LT4odgHJOu_Y{tBoT2aU;Hs$Q(1?4dpRs;V-h z-sG>UKAaj5)drfAz0@wrfjkL{U=<(+833XaK%oEx4tkTd)XfzcwIEyuULXy$tf5-M z`d4OqNSXjtW^RAur{ zGk#XE%O*1#%iAGK>+9+xb9D{%O!UBJ!~uP%XP{71qYwuYF~};`Ey>SL%`2YlU@R>S c=K=M@*}7nbAS)(2n@h5T3;;R?m?CBX0H4W}=l}o! diff --git a/example/index.ts b/example/index.ts index 9c20b7a..35c71dd 100644 --- a/example/index.ts +++ b/example/index.ts @@ -8,7 +8,11 @@ Bun.serve({ const response = await router.serve(request, { Shell: ExampleShell, bootstrapModules: ["/hydrate.js"], - noStreaming: true + noStreaming: true, + staticHeaders: { + "x-powered-by": "bun", + "cache-control": "max-age=14400, immutable", + }, }); if (response) return response; return new Response("Not found", { diff --git a/index.tsx b/index.tsx index 5147e1d..a6c4402 100644 --- a/index.tsx +++ b/index.tsx @@ -9,6 +9,7 @@ export class StaticRouters { readonly server: FileSystemRouter; readonly client: FileSystemRouter; readonly #routes_dump: string; + readonly #hashed: Record; constructor( public baseDir: string, @@ -23,12 +24,14 @@ export class StaticRouters { dir: join(baseDir, buildDir, pageDir), style: "nextjs", }); + this.#hashed = require(join(baseDir, buildDir, ".meta.json")).hashed; this.#routes_dump = NJSON.stringify( Object.fromEntries( - Object.entries(this.client.routes).map(([path, filePath]) => [ - path, - "/" + relative(join(baseDir, buildDir), filePath), - ]) + Object.entries(this.client.routes).map(([path, filePath]) => { + let target = "/" + relative(join(baseDir, buildDir), filePath); + if (this.#hashed[target]) target += `?${this.#hashed[target]}`; + return [path, target]; + }) ), { omitStack: true } ); @@ -46,6 +49,7 @@ export class StaticRouters { console.error(error, errorInfo); }, noStreaming, + staticHeaders, }: { Shell: React.ComponentType<{ children: React.ReactElement }>; preloadScript?: string; @@ -53,6 +57,7 @@ export class StaticRouters { context?: T; onError?(error: unknown, errorInfo: React.ErrorInfo): string | void; noStreaming?: boolean; + staticHeaders?: HeadersInit; } ): Promise { const { pathname, search } = new URL(request.url); @@ -60,7 +65,8 @@ export class StaticRouters { directory: this.buildDir, path: pathname, }); - if (staticResponse) return new Response(staticResponse); + if (staticResponse) + return new Response(staticResponse, { headers: staticHeaders }); const serverSide = this.server.match(request); if (!serverSide) return null; const clientSide = this.client.match(request); @@ -106,7 +112,11 @@ export class StaticRouters { ] .filter(Boolean) .join(";"), - bootstrapModules, + bootstrapModules: bootstrapModules?.map((name) => { + const hash = this.#hashed[name]; + if (hash) return `${name}?${hash}`; + return name; + }), onError, } ); diff --git a/package.json b/package.json index ecfd4fe..da12138 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ }, "peerDependencies": { "typescript": "^5.0.0", - "react": "*", - "react-dom": "*" + "react": "^19.0.0-rc-cc1ec60d0d-20240607", + "react-dom": "^19.0.0-rc-cc1ec60d0d-20240607" }, "dependencies": { "next-json": "^0.2.3"