the asset system is reworked to support "dynamic" entries, where each entry is a separate file on disk containing the latest generation's headers+raw+gzip+zstd. when calling view.regenerate, it will look for pages that had "export const regenerate" during generation, and render those pages using the view system, but then store the results as assets instead of sending as a response. pages configured as regenerable are also bundled as views, using the non-aliasing key "page:${page.id}". this cannot alias because file paths may not contain a colon.
111 lines
2.4 KiB
TypeScript
111 lines
2.4 KiB
TypeScript
// File System APIs. Some custom APIs, but mostly a re-export a mix of built-in
|
|
// Node.js sync+promise fs methods. For convenince.
|
|
export {
|
|
createReadStream,
|
|
createWriteStream,
|
|
existsSync,
|
|
type FileHandle,
|
|
open,
|
|
readdir,
|
|
readdirSync,
|
|
readFile,
|
|
readFileSync,
|
|
rm,
|
|
rmSync,
|
|
stat,
|
|
statSync,
|
|
writeFile,
|
|
writeFileSync,
|
|
};
|
|
|
|
export function mkdir(dir: string) {
|
|
return nodeMkdir(dir, { recursive: true });
|
|
}
|
|
|
|
export function mkdirSync(dir: string) {
|
|
return nodeMkdirSync(dir, { recursive: true });
|
|
}
|
|
|
|
export type WriteFileAsyncOptions = Parameters<typeof writeFile>[2];
|
|
|
|
export async function writeMkdir(
|
|
file: string,
|
|
contents: Buffer | string,
|
|
options?: WriteFileAsyncOptions,
|
|
) {
|
|
await mkdir(path.dirname(file));
|
|
return writeFile(file, contents, options);
|
|
}
|
|
|
|
export function writeMkdirSync(file: string, contents: Buffer | string) {
|
|
mkdirSync(path.dirname(file));
|
|
return writeFileSync(file, contents);
|
|
}
|
|
|
|
export function readDirRecOptionalSync(dir: string) {
|
|
try {
|
|
return readdirSync(dir, { recursive: true, encoding: "utf8" });
|
|
} catch (err: any) {
|
|
if (err.code === "ENOENT") return [];
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
export async function readJson<T>(file: string) {
|
|
return JSON.parse(await readFile(file, "utf-8")) as T;
|
|
}
|
|
|
|
export function readJsonSync<T>(file: string) {
|
|
return JSON.parse(readFileSync(file, "utf-8")) as T;
|
|
}
|
|
|
|
export async function removeEmptyDirectories(dir: string, removeRoot = false) {
|
|
try {
|
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
let len = entries.length;
|
|
for (const entry of entries) {
|
|
if (entry.isDirectory()) {
|
|
const subDirPath = path.join(dir, entry.name);
|
|
if (await removeEmptyDirectories(subDirPath, true)) len -= 1;
|
|
}
|
|
}
|
|
if (len === 0) {
|
|
if (removeRoot) {
|
|
await rmdir(dir);
|
|
}
|
|
return true;
|
|
}
|
|
} catch (error: any) {
|
|
if (error.code === "ENOENT") {
|
|
// Directory doesn't exist, ignore
|
|
return;
|
|
}
|
|
throw error;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
import * as path from "node:path";
|
|
import {
|
|
createReadStream,
|
|
createWriteStream,
|
|
existsSync,
|
|
mkdirSync as nodeMkdirSync,
|
|
readdirSync,
|
|
readFileSync,
|
|
rmSync,
|
|
statSync,
|
|
writeFileSync,
|
|
} from "node:fs";
|
|
import {
|
|
type FileHandle,
|
|
mkdir as nodeMkdir,
|
|
open,
|
|
readdir,
|
|
readFile,
|
|
rm,
|
|
rmdir,
|
|
stat,
|
|
writeFile,
|
|
} from "node:fs/promises";
|
|
export { Stats } from "node:fs";
|