//#region src/unplugin/dep-graph.d.ts /** * Static per-file dependency graphs, for disk-cache invalidation and for the * watch dependencies a loader host has to declare (see transformDependencies). * * The disk cache used to record `getFirstPartyModulePaths()` — the superset * of EVERY first-party module the loader had executed so far — as each * entry's dependency set. Supersets never serve stale results, but in a * large codebase every entry ends up recording the whole project (~1,900 * deps, ~400KB JSON per entry in the field report), so ANY commit * invalidates essentially the entire cache and CI re-pays full discovery * every run. * * This module computes the file's ACTUAL import graph statically: scan * import/export/require specifiers, resolve them (relative paths with * extension probing, tsconfig path aliases via the loader's config, bare * specifiers through node resolution), and BFS across first-party files. * No file is executed. Type-only imports are included (over-approximation * only over-invalidates). * * Soundness rule: when anything cannot be analyzed — a non-literal dynamic * import, an unresolvable relative specifier — the crawl reports * `complete: false` and the caller falls back to the superset. A static * crawl may only replace the superset when it provably covers everything * the file can load. * * Cost discipline (this runs serialized on the bundler's main process, once * per discovery file, over closures that reach thousands of files): * - every existence probe uses `statSync(p, { throwIfNoEntry: false })` — * a thrown ENOENT pays V8 error-plus-stack construction, and a cold crawl * issues these probes by the million (the dominant cost in field samples); * - resolution is memoized at every level: realpath per path, createRequire * per directory, resolved specifier per (directory, specifier), and the * full edge list per file (mtime-validated) — repeat crawls over the * shared core graph are Map lookups plus one cheap stat per file; * - the BFS aborts the moment the graph becomes unanalyzable: the caller * discards an incomplete result for the superset anyway, so finishing the * crawl would be pure waste (and incomplete is the COMMON outcome on * large graphs — one dynamic import anywhere poisons the whole closure). */ interface StaticDeps { /** Absolute real paths of first-party files reachable from the entry. */ deps: string[]; /** False when the graph could not be fully analyzed — use the superset. */ complete: boolean; } /** Reset the per-process dep-graph memos (watch-mode file changes). */ declare function resetDepGraphMemo(): void; /** * Compute the static first-party dependency closure of `entryFile`. * The entry itself is excluded (its content is part of the cache key). */ declare function collectStaticDeps(entryFile: string): StaticDeps; interface TransformDependencies { /** * Files to declare as watch dependencies, entry first and deduped. Complete * only when `complete` is true — otherwise it is just the entry. */ files: string[]; /** * False when the import graph could not be fully analyzed. `files` is then * NOT sufficient, and the host has to reach for a coarser signal (a context * dependency over the project, or refusing to cache the result) instead of * trusting it. */ complete: boolean; } /** * Files whose contents can change what `id`'s transform produces — the set a * host must declare as watch dependencies. * * Discovery EXECUTES the file's import graph, so a compiled validator reflects * every constant, enum and helper that graph contributed. A host that keys its * cache on `id`'s own content alone therefore serves a stale validator after an * edit to any of them. * * Bundler plugins do not need this: their `watchChange` hook fires for every * file in the project, so the plugin invalidates wholesale. Loader hosts * (Turbopack, plain webpack loaders) have no such hook — their only lever is * declaring dependencies per file, which is what this returns. * * The entry is always included, for the reason the disk cache records it too: a * host keys on the content it PASSED, but discovery executed the file from disk. * * Deliberately NOT backed by `getFirstPartyModulePaths()` when the crawl comes * up incomplete, unlike the disk cache's fallback. That superset is * point-in-time, not cumulative — `invalidateModuleCache()` empties it — so * after an unrelated file's discovery repopulates it, it describes THAT file's * graph and can silently omit this one's. The disk cache survives that because * `watchChange` invalidates wholesale and deferred entries flush against one * end-of-build snapshot; a loader host has neither backstop, so a plausible but * wrong list would go undetected. Reporting `complete: false` lets the caller * do the sound thing instead. */ declare function transformDependencies(id: string): TransformDependencies; //#endregion export { StaticDeps, TransformDependencies, collectStaticDeps, resetDepGraphMemo, transformDependencies }; //# sourceMappingURL=dep-graph.d.ts.map