SilverBullet pivot to become an offline-first PWA (#403)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { globToRegExp, path, walk } from "../deps.ts";
|
||||
import { globToRegExp, mime, path, walk } from "../deps.ts";
|
||||
import { AssetBundle } from "./bundle.ts";
|
||||
|
||||
export async function bundleAssets(
|
||||
@@ -23,21 +23,34 @@ export async function bundleAssets(
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
bundle.writeFileSync(cleanPath, await Deno.readFile(file.path));
|
||||
bundle.writeFileSync(
|
||||
cleanPath,
|
||||
mime.getType(cleanPath) || "application/octet-stream",
|
||||
await Deno.readFile(file.path),
|
||||
);
|
||||
}
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
export async function bundleFolder(rootPath: string, bundlePath: string) {
|
||||
export async function bundleFolder(
|
||||
rootPath: string,
|
||||
bundlePath: string,
|
||||
) {
|
||||
const bundle = new AssetBundle();
|
||||
await Deno.mkdir(path.dirname(bundlePath), { recursive: true });
|
||||
for await (
|
||||
const { path: filePath } of walk(rootPath, { includeDirs: false })
|
||||
) {
|
||||
console.log("Bundling", filePath);
|
||||
const stat = await Deno.stat(filePath);
|
||||
const cleanPath = filePath.substring(`${rootPath}/`.length);
|
||||
bundle.writeFileSync(cleanPath, await Deno.readFile(filePath));
|
||||
bundle.writeFileSync(
|
||||
cleanPath,
|
||||
mime.getType(filePath) || "application/octet-stream",
|
||||
await Deno.readFile(filePath),
|
||||
stat.mtime?.getTime(),
|
||||
);
|
||||
}
|
||||
await Deno.writeTextFile(
|
||||
bundlePath,
|
||||
|
||||
@@ -3,14 +3,14 @@ import { assertEquals } from "../../test_deps.ts";
|
||||
|
||||
Deno.test("Asset bundle", () => {
|
||||
const assetBundle = new AssetBundle();
|
||||
assetBundle.writeTextFileSync("test.txt", "Sup yo");
|
||||
assetBundle.writeTextFileSync("test.txt", "text/plain", "Sup yo");
|
||||
assertEquals("text/plain", assetBundle.getMimeType("test.txt"));
|
||||
assertEquals("Sup yo", assetBundle.readTextFileSync("test.txt"));
|
||||
const buf = new Uint8Array(3);
|
||||
buf[0] = 1;
|
||||
buf[1] = 2;
|
||||
buf[2] = 3;
|
||||
assetBundle.writeFileSync("test.bin", buf);
|
||||
assetBundle.writeFileSync("test.bin", "application/octet-stream", buf);
|
||||
assertEquals("application/octet-stream", assetBundle.getMimeType("test.bin"));
|
||||
assertEquals(buf, assetBundle.readFileSync("test.bin"));
|
||||
});
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { base64Decode, base64EncodedDataUrl } from "./base64.ts";
|
||||
import { mime } from "../deps.ts";
|
||||
|
||||
type DataUrl = string;
|
||||
|
||||
// Mapping from path -> `data:mimetype;base64,base64-encoded-data` strings
|
||||
export type AssetJson = Record<string, DataUrl>;
|
||||
export type AssetJson = Record<string, { data: DataUrl; mtime: number }>;
|
||||
|
||||
export class AssetBundle {
|
||||
readonly bundle: AssetJson;
|
||||
@@ -28,7 +27,7 @@ export class AssetBundle {
|
||||
if (!content) {
|
||||
throw new Error(`No such file ${path}`);
|
||||
}
|
||||
const data = content.split(",", 2)[1];
|
||||
const data = content.data.split(",", 2)[1];
|
||||
return base64Decode(data);
|
||||
}
|
||||
|
||||
@@ -37,7 +36,7 @@ export class AssetBundle {
|
||||
if (!content) {
|
||||
throw new Error(`No such file ${path}`);
|
||||
}
|
||||
return content;
|
||||
return content.data;
|
||||
}
|
||||
|
||||
readTextFileSync(
|
||||
@@ -49,22 +48,42 @@ export class AssetBundle {
|
||||
getMimeType(
|
||||
path: string,
|
||||
): string {
|
||||
const content = this.bundle[path];
|
||||
if (!content) {
|
||||
const entry = this.bundle[path];
|
||||
if (!entry) {
|
||||
throw new Error(`No such file ${path}`);
|
||||
}
|
||||
return content.split(";")[0].split(":")[1];
|
||||
return entry.data.split(";")[0].split(":")[1];
|
||||
}
|
||||
|
||||
writeFileSync(path: string, data: Uint8Array) {
|
||||
getMtime(path: string): number {
|
||||
const entry = this.bundle[path];
|
||||
if (!entry) {
|
||||
throw new Error(`No such file ${path}`);
|
||||
}
|
||||
return entry.mtime;
|
||||
}
|
||||
|
||||
writeFileSync(
|
||||
path: string,
|
||||
mimeType: string,
|
||||
data: Uint8Array,
|
||||
mtime: number = Date.now(),
|
||||
) {
|
||||
// Replace \ with / for windows
|
||||
path = path.replaceAll("\\", "/");
|
||||
const mimeType = mime.getType(path) || "application/octet-stream";
|
||||
this.bundle[path] = base64EncodedDataUrl(mimeType, data);
|
||||
this.bundle[path] = {
|
||||
data: base64EncodedDataUrl(mimeType, data),
|
||||
mtime,
|
||||
};
|
||||
}
|
||||
|
||||
writeTextFileSync(path: string, s: string) {
|
||||
this.writeFileSync(path, new TextEncoder().encode(s));
|
||||
writeTextFileSync(
|
||||
path: string,
|
||||
mimeType: string,
|
||||
s: string,
|
||||
mtime: number = Date.now(),
|
||||
) {
|
||||
this.writeFileSync(path, mimeType, new TextEncoder().encode(s), mtime);
|
||||
}
|
||||
|
||||
toJSON(): AssetJson {
|
||||
|
||||
Reference in New Issue
Block a user