Fix build lags
This commit is contained in:
@@ -2,51 +2,111 @@ import { log } from "../../utils/log";
|
||||
import path from "path";
|
||||
import grabDirNames from "../../utils/grab-dir-names";
|
||||
import { existsSync, readdirSync, statSync, unlinkSync } from "fs";
|
||||
import type { BundlerCTXMap } from "../../types";
|
||||
|
||||
type Params = {
|
||||
new_artifacts: BundlerCTXMap[];
|
||||
paradigm: "hydration" | "ssr";
|
||||
};
|
||||
|
||||
const { ROOT_DIR, HYDRATION_DST_DIR_MAP_JSON_FILE_NAME } = grabDirNames();
|
||||
const { ROOT_DIR, HYDRATION_DST_DIR, BUNX_CWD_MODULE_CACHE_DIR } =
|
||||
grabDirNames();
|
||||
|
||||
// esbuild's content hashes are 8-char base64-ish (e.g. `CMSI7VSQ`). Entry
|
||||
// outputs are `<dir>/<hash>.js` / `<dir>/<hash>.css`. Shared chunks are
|
||||
// `chunk-*.js` and MUST be kept: any current entry may still reference an
|
||||
// older chunk (esbuild reuses unchanged chunks across rebuilds), and
|
||||
// verifying references would require parsing every entry's imports.
|
||||
const ENTRY_HASH_FILE = /^[A-Za-z0-9]{8}\.(js|css)$/;
|
||||
|
||||
/**
|
||||
* Deletes orphaned entry outputs left behind by previous rebuilds.
|
||||
*
|
||||
* After a rebuild the page/SSR artifact maps only reference the newest
|
||||
* hashed entry files; every previously hashed entry for the same directory
|
||||
* is provably unreferenced (generated HTML always uses the current map) and
|
||||
* is removed. Chunks, non-hashed fallback module files and `map.json` are
|
||||
* left untouched.
|
||||
*/
|
||||
export default async function cleanupArtifacts({ paradigm }: Params) {
|
||||
const is_hydration = paradigm === "hydration";
|
||||
const root_dir = is_hydration
|
||||
? HYDRATION_DST_DIR
|
||||
: BUNX_CWD_MODULE_CACHE_DIR;
|
||||
const map = is_hydration
|
||||
? global.BUNEXT_BUNDLER_CTX_MAP
|
||||
: global.BUNEXT_SSR_BUNDLER_CTX_MAP;
|
||||
|
||||
if (!map || !existsSync(root_dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
export default async function cleanupArtifacts({ new_artifacts }: Params) {
|
||||
try {
|
||||
for (let i = 0; i < new_artifacts.length; i++) {
|
||||
const new_artifact = new_artifacts[i];
|
||||
const keep_by_dir = new Map<string, Set<string>>();
|
||||
|
||||
const artifact_public_dir = path.dirname(
|
||||
path.join(ROOT_DIR, new_artifact.path),
|
||||
);
|
||||
for (const entry of Object.values(map)) {
|
||||
if (!entry?.path) continue;
|
||||
|
||||
const dir_content = readdirSync(artifact_public_dir);
|
||||
const full_path = path.join(ROOT_DIR, entry.path);
|
||||
const dir_path = path.dirname(full_path);
|
||||
let keep = keep_by_dir.get(dir_path);
|
||||
if (!keep) {
|
||||
keep = new Set<string>();
|
||||
keep_by_dir.set(dir_path, keep);
|
||||
}
|
||||
|
||||
for (let d = 0; d < dir_content.length; d++) {
|
||||
const dir_or_file = dir_content[d];
|
||||
const full_path = path.join(artifact_public_dir, dir_or_file);
|
||||
keep.add(path.basename(full_path));
|
||||
|
||||
const file_or_path_stats = statSync(full_path);
|
||||
|
||||
if (
|
||||
file_or_path_stats.isDirectory() ||
|
||||
dir_or_file == HYDRATION_DST_DIR_MAP_JSON_FILE_NAME
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
new_artifact.path.includes(dir_or_file) ||
|
||||
new_artifact.css_path?.includes(dir_or_file)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (existsSync(full_path)) {
|
||||
unlinkSync(full_path);
|
||||
}
|
||||
if (entry.css_path) {
|
||||
keep.add(path.basename(entry.css_path));
|
||||
}
|
||||
}
|
||||
|
||||
sweepDir(root_dir, keep_by_dir);
|
||||
} catch (error: any) {
|
||||
log.error(error);
|
||||
log.error(`Cleanup Artifacts Error: ${error?.message || error}`);
|
||||
}
|
||||
}
|
||||
|
||||
function sweepDir(
|
||||
dir_path: string,
|
||||
keep_by_dir: Map<string, Set<string>>,
|
||||
): void {
|
||||
let entries: string[];
|
||||
try {
|
||||
entries = readdirSync(dir_path);
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const name of entries) {
|
||||
const full_path = path.join(dir_path, name);
|
||||
|
||||
let is_dir = false;
|
||||
try {
|
||||
is_dir = statSync(full_path).isDirectory();
|
||||
} catch (error) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_dir) {
|
||||
sweepDir(full_path, keep_by_dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!name.match(ENTRY_HASH_FILE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name.startsWith("chunk-")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const keep = keep_by_dir.get(path.dirname(full_path));
|
||||
if (keep?.has(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
unlinkSync(full_path);
|
||||
} catch (error) {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user