40 lines
1.4 KiB
JavaScript
40 lines
1.4 KiB
JavaScript
import { createHash } from "node:crypto";
|
|
import { readFile, writeFile, readdir } from "node:fs/promises";
|
|
import path from "node:path";
|
|
|
|
const PLACEHOLDER = "__ASSET_VERSION__";
|
|
const root = path.resolve(process.argv[2] || process.cwd());
|
|
const assetRoots = ["public", "shared"];
|
|
|
|
async function walk(directory) {
|
|
const entries = await readdir(directory, { withFileTypes: true });
|
|
const files = await Promise.all(
|
|
entries.map((entry) => {
|
|
const target = path.join(directory, entry.name);
|
|
return entry.isDirectory() ? walk(target) : target;
|
|
}),
|
|
);
|
|
return files.flat().sort();
|
|
}
|
|
|
|
const files = (
|
|
await Promise.all(assetRoots.map((directory) => walk(path.join(root, directory))))
|
|
).flat();
|
|
const sources = await Promise.all(files.map((file) => readFile(file, "utf8")));
|
|
const version = createHash("sha256")
|
|
.update(files.map((file, index) => `${path.relative(root, file)}\0${sources[index]}`).join("\0"))
|
|
.digest("hex")
|
|
.slice(0, 16);
|
|
let replacements = 0;
|
|
await Promise.all(
|
|
files.map(async (file, index) => {
|
|
const source = sources[index];
|
|
const count = source.split(PLACEHOLDER).length - 1;
|
|
if (!count) return;
|
|
replacements += count;
|
|
await writeFile(file, source.replaceAll(PLACEHOLDER, version));
|
|
}),
|
|
);
|
|
if (!replacements) throw new Error(`No ${PLACEHOLDER} markers found under ${assetRoots.join(", ")}.`);
|
|
console.log(`Stamped ${replacements} asset references with version ${version}.`);
|