Skip to content

Commit 724f707

Browse files
xiaoxiaojxclaude
andcommitted
fix: share join/dirname caches across resolvers via fileSystem WeakMap
Use fileSystem as the cache owner so that multiple Resolver instances sharing the same fileSystem (e.g. across webpack recompilations) reuse the same join/dirname caches. When the fileSystem is garbage collected, the caches are released via WeakMap. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5e38acc commit 724f707

2 files changed

Lines changed: 44 additions & 3 deletions

File tree

lib/Resolver.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ const {
1818
normalize,
1919
} = require("./util/path");
2020

21+
/**
22+
* @typedef {object} PathCacheFunctions
23+
* @property {(rootPath: string, request: string) => string} join cached join
24+
* @property {(maybePath: string) => string} dirname cached dirname
25+
*/
26+
27+
/** @type {WeakMap<FileSystem, PathCacheFunctions>} */
28+
const _pathCacheByFs = new WeakMap();
29+
2130
/** @typedef {import("./ResolverFactory").ResolveOptions} ResolveOptions */
2231

2332
/**
@@ -400,8 +409,21 @@ class Resolver {
400409
constructor(fileSystem, options) {
401410
this.fileSystem = fileSystem;
402411
this.options = options;
403-
this.join = options.unsafeCache ? createCachedJoin() : _join;
404-
this.dirname = options.unsafeCache ? createCachedDirname() : _dirname;
412+
if (options.unsafeCache) {
413+
let pathCache = _pathCacheByFs.get(fileSystem);
414+
if (!pathCache) {
415+
pathCache = {
416+
join: createCachedJoin(),
417+
dirname: createCachedDirname(),
418+
};
419+
_pathCacheByFs.set(fileSystem, pathCache);
420+
}
421+
this.join = pathCache.join;
422+
this.dirname = pathCache.dirname;
423+
} else {
424+
this.join = _join;
425+
this.dirname = _dirname;
426+
}
405427
/** @type {KnownHooks} */
406428
this.hooks = {
407429
resolveStep: new SyncHook(["hook", "request"], "resolveStep"),

test/resolver-cache.test.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ describe("Resolver join/dirname cache", () => {
1919
expect(resolver.dirname).not.toBe(dirname);
2020
});
2121

22-
it("should create independent caches per resolver", () => {
22+
it("should share caches across resolvers with the same fileSystem", () => {
2323
const fileSystem = new CachedInputFileSystem(fs, 0);
2424

2525
const resolver1 = ResolverFactory.createResolver({
@@ -33,6 +33,25 @@ describe("Resolver join/dirname cache", () => {
3333
unsafeCache: true,
3434
});
3535

36+
expect(resolver1.join).toBe(resolver2.join);
37+
expect(resolver1.dirname).toBe(resolver2.dirname);
38+
});
39+
40+
it("should use independent caches for different fileSystems", () => {
41+
const fileSystem1 = new CachedInputFileSystem(fs, 0);
42+
const fileSystem2 = new CachedInputFileSystem(fs, 0);
43+
44+
const resolver1 = ResolverFactory.createResolver({
45+
fileSystem: fileSystem1,
46+
extensions: [".js"],
47+
unsafeCache: true,
48+
});
49+
const resolver2 = ResolverFactory.createResolver({
50+
fileSystem: fileSystem2,
51+
extensions: [".js"],
52+
unsafeCache: true,
53+
});
54+
3655
expect(resolver1.join).not.toBe(resolver2.join);
3756
expect(resolver1.dirname).not.toBe(resolver2.dirname);
3857
});

0 commit comments

Comments
 (0)