forked from denoland/fresh
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
218 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { getFile, housekeep, isSupported, saveFile } from "./kvfs.ts"; | ||
|
||
const IS_CHUNK = /\/chunk-[a-zA-Z0-9]*.js/; | ||
const DEPENDENCIES_SNAP = "dependencies.snap.json"; | ||
|
||
export const getDependencies = async () => { | ||
const deps = await getFile(DEPENDENCIES_SNAP); | ||
|
||
if (!deps) { | ||
return null; | ||
} | ||
|
||
const json = await new Response(deps).json(); | ||
return new Map<string, string[]>(json); | ||
}; | ||
|
||
export const saveDependencies = (deps: Map<string, string[]>) => | ||
saveFile( | ||
DEPENDENCIES_SNAP, | ||
new TextEncoder().encode( | ||
JSON.stringify([...deps.entries()]), | ||
), | ||
); | ||
|
||
export const saveSnapshot = async ( | ||
filesystem: Map<string, Uint8Array>, | ||
dependencies: Map<string, string[]>, | ||
) => { | ||
if (!isSupported()) return; | ||
|
||
// We need to save chunks first, islands/plugins last so we address esm.sh build instabilities | ||
const chunksFirst = [...filesystem.keys()].sort((a, b) => { | ||
const aIsChunk = IS_CHUNK.test(a); | ||
const bIsChunk = IS_CHUNK.test(b); | ||
const cmp = a > b ? 1 : a < b ? -1 : 0; | ||
return aIsChunk && bIsChunk ? cmp : aIsChunk ? -10 : bIsChunk ? 10 : cmp; | ||
}); | ||
|
||
let start = performance.now(); | ||
for (const path of chunksFirst) { | ||
const content = filesystem.get(path); | ||
|
||
if (content instanceof ReadableStream) { | ||
console.info("streams are not yet supported on KVFS"); | ||
return; | ||
} | ||
|
||
if (content) await saveFile(path, content); | ||
} | ||
|
||
const deps = new Map<string, string[]>(); | ||
for (const dep of chunksFirst) { | ||
deps.set(dep, dependencies.get(dep)!); | ||
} | ||
await saveDependencies(deps); | ||
|
||
let dur = (performance.now() - start) / 1e3; | ||
console.log(` 💾 Save bundle to Deno.KV: ${dur.toFixed(2)}s`); | ||
|
||
start = performance.now(); | ||
await housekeep(); | ||
dur = (performance.now() - start) / 1e3; | ||
console.log(` 🧹 Housekeep Deno.KV: ${dur.toFixed(2)}s`); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { BUILD_ID } from "../server/build_id.ts"; | ||
|
||
const CHUNKSIZE = 65536; | ||
const NAMESPACE = ["_frsh", "js", BUILD_ID]; | ||
|
||
// @ts-ignore as `Deno.openKv` is still unstable. | ||
const kv = await Deno.openKv?.().catch((e) => { | ||
console.error(e); | ||
|
||
return null; | ||
}); | ||
|
||
export const isSupported = () => kv != null; | ||
|
||
export const getFile = async (file: string) => { | ||
if (!isSupported()) return null; | ||
|
||
const filepath = [...NAMESPACE, file]; | ||
const metadata = await kv!.get(filepath).catch(() => null); | ||
|
||
if (metadata?.versionstamp == null) { | ||
return null; | ||
} | ||
|
||
console.log(` 🚣 Streaming from Deno.KV ${file}`); | ||
|
||
return new ReadableStream<Uint8Array>({ | ||
start: async (sink) => { | ||
for await (const chunk of kv!.list({ prefix: filepath })) { | ||
sink.enqueue(chunk.value as Uint8Array); | ||
} | ||
sink.close(); | ||
}, | ||
}); | ||
}; | ||
|
||
export const saveFile = async (file: string, content: Uint8Array) => { | ||
if (!isSupported()) return null; | ||
|
||
const filepath = [...NAMESPACE, file]; | ||
const metadata = await kv!.get(filepath); | ||
|
||
// Current limitation: As of May 2023, KV Transactions only support a maximum of 10 operations. | ||
let transaction = kv!.atomic(); | ||
let chunks = 0; | ||
for (; chunks * CHUNKSIZE < content.length; chunks++) { | ||
transaction = transaction.set( | ||
[...filepath, chunks], | ||
content.slice(chunks * CHUNKSIZE, (chunks + 1) * CHUNKSIZE), | ||
); | ||
} | ||
const result = await transaction | ||
.set(filepath, chunks) | ||
.check(metadata) | ||
.commit(); | ||
|
||
return result.ok; | ||
}; | ||
|
||
export const housekeep = async () => { | ||
if (!isSupported()) return null; | ||
|
||
for await ( | ||
const item of kv!.list({ prefix: ["_frsh", "js"] }) | ||
) { | ||
if (item.key.includes(BUILD_ID)) continue; | ||
|
||
await kv!.delete(item.key); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.