From 45149af01ee65982ccab7735caf4fd05418dd7aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 9 Jul 2025 09:02:35 +0000 Subject: [PATCH 1/4] Initial plan From 65a1c5384be7b521a614d8ebb8f89d854596c924 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 9 Jul 2025 09:12:37 +0000 Subject: [PATCH 2/4] Implement ResolverFactory hooks: resolveOptions and resolver Co-authored-by: SyMind <19852293+SyMind@users.noreply.github.com> --- packages/rspack/src/ResolverFactory.ts | 34 +++++++++++++++++-- test-resolver-factory-hooks.js | 43 ++++++++++++++++++++++++ test-resolver-factory-hooks.ts | 45 ++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 test-resolver-factory-hooks.js create mode 100644 test-resolver-factory-hooks.ts diff --git a/packages/rspack/src/ResolverFactory.ts b/packages/rspack/src/ResolverFactory.ts index cfc5f6c2b739..a7ef137c7181 100644 --- a/packages/rspack/src/ResolverFactory.ts +++ b/packages/rspack/src/ResolverFactory.ts @@ -1,4 +1,5 @@ import * as binding from "@rspack/binding"; +import * as liteTapable from "@rspack/lite-tapable"; import { Resolver } from "./Resolver"; import { type Resolve, getRawResolve } from "./config"; @@ -10,6 +11,13 @@ type ResolveOptionsWithDependencyType = Resolve & { export class ResolverFactory { #binding: binding.JsResolverFactory; + hooks: { + resolveOptions: liteTapable.SyncWaterfallHook< + [ResolveOptionsWithDependencyType, { type: string }] + >; + resolver: liteTapable.SyncHook<[Resolver, ResolveOptionsWithDependencyType, { type: string }]>; + }; + static __to_binding( resolver_factory: ResolverFactory ): binding.JsResolverFactory { @@ -18,20 +26,42 @@ export class ResolverFactory { constructor(pnp: boolean) { this.#binding = new binding.JsResolverFactory(pnp); + this.hooks = { + resolveOptions: new liteTapable.SyncWaterfallHook([ + "resolveOptions", + "context" + ]), + resolver: new liteTapable.SyncHook(["resolver", "resolveOptions", "context"]) + }; } get( type: string, resolveOptions?: ResolveOptionsWithDependencyType ): Resolver { + // Prepare context for hooks + const context = { type }; + + // Apply resolveOptions hook to allow modification of resolve options + const resolveOptionsToUse = this.hooks.resolveOptions.call( + resolveOptions || {}, + context + ); + const { dependencyCategory, resolveToContext, ...resolve } = - resolveOptions || {}; + resolveOptionsToUse; const binding = this.#binding.get(type, { ...getRawResolve(resolve), dependencyCategory, resolveToContext }); - return new Resolver(binding); + + const resolver = new Resolver(binding); + + // Call resolver hook to allow plugins to access the created resolver + this.hooks.resolver.call(resolver, resolveOptionsToUse, context); + + return resolver; } } diff --git a/test-resolver-factory-hooks.js b/test-resolver-factory-hooks.js new file mode 100644 index 000000000000..e018138501cb --- /dev/null +++ b/test-resolver-factory-hooks.js @@ -0,0 +1,43 @@ +// Simple test to verify ResolverFactory hooks are working +const { ResolverFactory } = require('./packages/rspack/dist/index.js'); + +console.log('Testing ResolverFactory hooks...'); + +const resolverFactory = new ResolverFactory(false); + +// Test that hooks exist +console.log('resolveOptions hook exists:', !!resolverFactory.hooks.resolveOptions); +console.log('resolver hook exists:', !!resolverFactory.hooks.resolver); + +// Test resolveOptions hook +let resolveOptionsHookCalled = false; +resolverFactory.hooks.resolveOptions.tap('TestPlugin', (resolveOptions, context) => { + console.log('resolveOptions hook called with:', { type: context.type, resolveOptions }); + resolveOptionsHookCalled = true; + // Return modified options + return { ...resolveOptions, test: true }; +}); + +// Test resolver hook +let resolverHookCalled = false; +resolverFactory.hooks.resolver.tap('TestPlugin', (resolver, resolveOptions, context) => { + console.log('resolver hook called with:', { type: context.type, resolverExists: !!resolver }); + resolverHookCalled = true; +}); + +// Create a resolver to trigger hooks +try { + const resolver = resolverFactory.get('normal', { mainFields: ['main'] }); + console.log('Resolver created successfully:', !!resolver); + + console.log('resolveOptions hook was called:', resolveOptionsHookCalled); + console.log('resolver hook was called:', resolverHookCalled); + + if (resolveOptionsHookCalled && resolverHookCalled) { + console.log('✅ All tests passed! ResolverFactory hooks are working correctly.'); + } else { + console.log('❌ Some hooks were not called.'); + } +} catch (error) { + console.error('Error creating resolver:', error); +} \ No newline at end of file diff --git a/test-resolver-factory-hooks.ts b/test-resolver-factory-hooks.ts new file mode 100644 index 000000000000..b3f28353f404 --- /dev/null +++ b/test-resolver-factory-hooks.ts @@ -0,0 +1,45 @@ +// TypeScript test for ResolverFactory hooks interface +import * as liteTapable from "@rspack/lite-tapable"; +import { ResolverFactory } from "./packages/rspack/src/ResolverFactory"; +import { Resolver } from "./packages/rspack/src/Resolver"; + +// Type-only test to verify the hooks interface is correct +type ResolverFactoryTest = { + hooks: { + resolveOptions: liteTapable.SyncWaterfallHook<[any, { type: string }]>; + resolver: liteTapable.SyncHook<[Resolver, any, { type: string }]>; + }; +}; + +// This should compile without errors if the types are correct +function testHooksInterface(factory: ResolverFactory): void { + // Test that hooks exist and have correct types + const hooks: ResolverFactoryTest["hooks"] = factory.hooks; + + // Test resolveOptions hook signature + factory.hooks.resolveOptions.tap("test", (resolveOptions, context) => { + console.log("Type test:", context.type, resolveOptions); + return resolveOptions; + }); + + // Test resolver hook signature + factory.hooks.resolver.tap("test", (resolver, resolveOptions, context) => { + console.log("Type test:", context.type, resolver, resolveOptions); + }); +} + +// Test that constructor creates hooks +function testConstructor(): void { + // This test verifies that the hooks are properly initialized + const factory = new ResolverFactory(false); + + // Verify hooks exist + console.assert(factory.hooks.resolveOptions !== undefined, "resolveOptions hook should exist"); + console.assert(factory.hooks.resolver !== undefined, "resolver hook should exist"); + + // Verify hooks are instances of correct types + console.assert(factory.hooks.resolveOptions instanceof liteTapable.SyncWaterfallHook, "resolveOptions should be SyncWaterfallHook"); + console.assert(factory.hooks.resolver instanceof liteTapable.SyncHook, "resolver should be SyncHook"); +} + +console.log("TypeScript interface test passed!"); \ No newline at end of file From 6820b1b60374c841d2dd7b72e1d218b908e2d85a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 9 Jul 2025 09:15:19 +0000 Subject: [PATCH 3/4] Format ResolverFactory.ts and remove test files Co-authored-by: SyMind <19852293+SyMind@users.noreply.github.com> --- packages/rspack/src/ResolverFactory.ts | 18 +++++++---- test-resolver-factory-hooks.js | 43 ------------------------ test-resolver-factory-hooks.ts | 45 -------------------------- 3 files changed, 12 insertions(+), 94 deletions(-) delete mode 100644 test-resolver-factory-hooks.js delete mode 100644 test-resolver-factory-hooks.ts diff --git a/packages/rspack/src/ResolverFactory.ts b/packages/rspack/src/ResolverFactory.ts index a7ef137c7181..078c0086943e 100644 --- a/packages/rspack/src/ResolverFactory.ts +++ b/packages/rspack/src/ResolverFactory.ts @@ -15,7 +15,9 @@ export class ResolverFactory { resolveOptions: liteTapable.SyncWaterfallHook< [ResolveOptionsWithDependencyType, { type: string }] >; - resolver: liteTapable.SyncHook<[Resolver, ResolveOptionsWithDependencyType, { type: string }]>; + resolver: liteTapable.SyncHook< + [Resolver, ResolveOptionsWithDependencyType, { type: string }] + >; }; static __to_binding( @@ -31,7 +33,11 @@ export class ResolverFactory { "resolveOptions", "context" ]), - resolver: new liteTapable.SyncHook(["resolver", "resolveOptions", "context"]) + resolver: new liteTapable.SyncHook([ + "resolver", + "resolveOptions", + "context" + ]) }; } @@ -41,7 +47,7 @@ export class ResolverFactory { ): Resolver { // Prepare context for hooks const context = { type }; - + // Apply resolveOptions hook to allow modification of resolve options const resolveOptionsToUse = this.hooks.resolveOptions.call( resolveOptions || {}, @@ -56,12 +62,12 @@ export class ResolverFactory { dependencyCategory, resolveToContext }); - + const resolver = new Resolver(binding); - + // Call resolver hook to allow plugins to access the created resolver this.hooks.resolver.call(resolver, resolveOptionsToUse, context); - + return resolver; } } diff --git a/test-resolver-factory-hooks.js b/test-resolver-factory-hooks.js deleted file mode 100644 index e018138501cb..000000000000 --- a/test-resolver-factory-hooks.js +++ /dev/null @@ -1,43 +0,0 @@ -// Simple test to verify ResolverFactory hooks are working -const { ResolverFactory } = require('./packages/rspack/dist/index.js'); - -console.log('Testing ResolverFactory hooks...'); - -const resolverFactory = new ResolverFactory(false); - -// Test that hooks exist -console.log('resolveOptions hook exists:', !!resolverFactory.hooks.resolveOptions); -console.log('resolver hook exists:', !!resolverFactory.hooks.resolver); - -// Test resolveOptions hook -let resolveOptionsHookCalled = false; -resolverFactory.hooks.resolveOptions.tap('TestPlugin', (resolveOptions, context) => { - console.log('resolveOptions hook called with:', { type: context.type, resolveOptions }); - resolveOptionsHookCalled = true; - // Return modified options - return { ...resolveOptions, test: true }; -}); - -// Test resolver hook -let resolverHookCalled = false; -resolverFactory.hooks.resolver.tap('TestPlugin', (resolver, resolveOptions, context) => { - console.log('resolver hook called with:', { type: context.type, resolverExists: !!resolver }); - resolverHookCalled = true; -}); - -// Create a resolver to trigger hooks -try { - const resolver = resolverFactory.get('normal', { mainFields: ['main'] }); - console.log('Resolver created successfully:', !!resolver); - - console.log('resolveOptions hook was called:', resolveOptionsHookCalled); - console.log('resolver hook was called:', resolverHookCalled); - - if (resolveOptionsHookCalled && resolverHookCalled) { - console.log('✅ All tests passed! ResolverFactory hooks are working correctly.'); - } else { - console.log('❌ Some hooks were not called.'); - } -} catch (error) { - console.error('Error creating resolver:', error); -} \ No newline at end of file diff --git a/test-resolver-factory-hooks.ts b/test-resolver-factory-hooks.ts deleted file mode 100644 index b3f28353f404..000000000000 --- a/test-resolver-factory-hooks.ts +++ /dev/null @@ -1,45 +0,0 @@ -// TypeScript test for ResolverFactory hooks interface -import * as liteTapable from "@rspack/lite-tapable"; -import { ResolverFactory } from "./packages/rspack/src/ResolverFactory"; -import { Resolver } from "./packages/rspack/src/Resolver"; - -// Type-only test to verify the hooks interface is correct -type ResolverFactoryTest = { - hooks: { - resolveOptions: liteTapable.SyncWaterfallHook<[any, { type: string }]>; - resolver: liteTapable.SyncHook<[Resolver, any, { type: string }]>; - }; -}; - -// This should compile without errors if the types are correct -function testHooksInterface(factory: ResolverFactory): void { - // Test that hooks exist and have correct types - const hooks: ResolverFactoryTest["hooks"] = factory.hooks; - - // Test resolveOptions hook signature - factory.hooks.resolveOptions.tap("test", (resolveOptions, context) => { - console.log("Type test:", context.type, resolveOptions); - return resolveOptions; - }); - - // Test resolver hook signature - factory.hooks.resolver.tap("test", (resolver, resolveOptions, context) => { - console.log("Type test:", context.type, resolver, resolveOptions); - }); -} - -// Test that constructor creates hooks -function testConstructor(): void { - // This test verifies that the hooks are properly initialized - const factory = new ResolverFactory(false); - - // Verify hooks exist - console.assert(factory.hooks.resolveOptions !== undefined, "resolveOptions hook should exist"); - console.assert(factory.hooks.resolver !== undefined, "resolver hook should exist"); - - // Verify hooks are instances of correct types - console.assert(factory.hooks.resolveOptions instanceof liteTapable.SyncWaterfallHook, "resolveOptions should be SyncWaterfallHook"); - console.assert(factory.hooks.resolver instanceof liteTapable.SyncHook, "resolver should be SyncHook"); -} - -console.log("TypeScript interface test passed!"); \ No newline at end of file From 835c4d97b88b544ea109b9b08b3c335d12425c4a Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 9 Jul 2025 17:38:03 +0800 Subject: [PATCH 4/4] chore: resolver should be HookMap --- packages/rspack/src/ResolverFactory.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/rspack/src/ResolverFactory.ts b/packages/rspack/src/ResolverFactory.ts index 078c0086943e..a1dd2bcd1fdd 100644 --- a/packages/rspack/src/ResolverFactory.ts +++ b/packages/rspack/src/ResolverFactory.ts @@ -15,8 +15,10 @@ export class ResolverFactory { resolveOptions: liteTapable.SyncWaterfallHook< [ResolveOptionsWithDependencyType, { type: string }] >; - resolver: liteTapable.SyncHook< - [Resolver, ResolveOptionsWithDependencyType, { type: string }] + resolver: liteTapable.HookMap< + liteTapable.SyncHook< + [Resolver, ResolveOptionsWithDependencyType, { type: string }] + > >; }; @@ -33,11 +35,10 @@ export class ResolverFactory { "resolveOptions", "context" ]), - resolver: new liteTapable.SyncHook([ - "resolver", - "resolveOptions", - "context" - ]) + resolver: new liteTapable.HookMap( + () => + new liteTapable.SyncHook(["resolver", "resolveOptions", "context"]) + ) }; } @@ -66,7 +67,7 @@ export class ResolverFactory { const resolver = new Resolver(binding); // Call resolver hook to allow plugins to access the created resolver - this.hooks.resolver.call(resolver, resolveOptionsToUse, context); + this.hooks.resolver.for(type).call(resolver, resolveOptionsToUse, context); return resolver; }