82 lines
2.2 KiB
JavaScript
82 lines
2.2 KiB
JavaScript
import fs from "node:fs/promises";
|
|
import { posix as path } from "node:path";
|
|
import { fsCachePath } from "../../utils/runtimeChecks.js";
|
|
|
|
const copied = new Set();
|
|
const dirsCreated = new Set();
|
|
|
|
export async function saveAndCopyAsset(
|
|
hash,
|
|
image,
|
|
buffer,
|
|
outDir,
|
|
assetsDir,
|
|
assetPath,
|
|
isSsrBuild
|
|
) {
|
|
// Use Set for O(1) lookup instead of O(n) array search
|
|
if (copied.has(assetPath)) return;
|
|
|
|
const src = fsCachePath + hash;
|
|
const dest = path.join(outDir, isSsrBuild ? "/client" : "", assetPath);
|
|
const destDir = path.dirname(dest);
|
|
|
|
// Check if destination already exists and is valid (skip copy)
|
|
try {
|
|
const stats = await fs.stat(dest);
|
|
if (stats.size > 0) {
|
|
copied.add(assetPath);
|
|
console.log(`[skip] ${assetPath} (already exists)`);
|
|
return;
|
|
}
|
|
} catch {
|
|
// File doesn't exist, continue with copy
|
|
}
|
|
|
|
// Ensure destination directory exists (but only create once per unique dir)
|
|
if (!dirsCreated.has(destDir)) {
|
|
await fs.mkdir(destDir, { recursive: true });
|
|
dirsCreated.add(destDir);
|
|
}
|
|
|
|
// Try hardlink first (instant, no disk usage), fallback to copy
|
|
let linked = false;
|
|
try {
|
|
await fs.link(src, dest);
|
|
linked = true;
|
|
} catch (linkError) {
|
|
// Hardlink failed, try copy
|
|
try {
|
|
await fs.copyFile(src, dest);
|
|
} catch (copyError) {
|
|
if (copyError.code === "ENOENT") {
|
|
// Source doesn't exist, regenerate from buffer/image
|
|
const imageBuffer = buffer || (await image.toBuffer());
|
|
await Promise.all([
|
|
fs.writeFile(src, imageBuffer),
|
|
fs.writeFile(dest, imageBuffer)
|
|
]);
|
|
console.log(`[regen] ${src} -> ${dest}`);
|
|
} else {
|
|
throw copyError;
|
|
}
|
|
}
|
|
}
|
|
|
|
copied.add(assetPath);
|
|
}
|
|
|
|
// Helper to pre-create directories in batch (call before processing)
|
|
export async function preCreateDirectories(assetPaths, outDir, isSsrBuild) {
|
|
const uniqueDirs = new Set(
|
|
assetPaths.map(assetPath =>
|
|
path.dirname(path.join(outDir, isSsrBuild ? "/client" : "", assetPath))
|
|
)
|
|
);
|
|
|
|
await Promise.all(
|
|
[...uniqueDirs].map(dir => fs.mkdir(dir, { recursive: true }))
|
|
);
|
|
uniqueDirs.forEach(dir => dirsCreated.add(dir));
|
|
}
|