Skip to content

Commit d20c7d0

Browse files
committed
fix webpack resolver state leakage
I found a case where we were accidentally leaking state between WebpackModuleRequests. This is hard to avoid since webpack *really* pushes us toward using mutation on the shared ResolveData object. I solved it by making our mutations happen only at the precise moment when we're letting a request bubble back out to webpack. This is expected to fail tests however because this bug was masking another bug. Specifically, we have several test apps that use things like the `page-title` helper. That helper is (1) used with ambiguous syntax, (2) published in a v2 addon. It turns out we cannot resolve the helper due to #1686, and this was only "working" by accident since the failed attempt at resolving the helper got leaked back to webpack and webpack *does* understand package.json exports and would find it.
1 parent 014abac commit d20c7d0

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

packages/webpack/src/webpack-resolver-plugin.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,28 @@ class WebpackModuleRequest implements ModuleRequest {
176176
return 'webpack';
177177
}
178178

179+
// Webpack mostly relies on mutation to adjust requests. We could create a
180+
// whole new ResolveData instead, and that would allow defaultResolving to
181+
// happen, but for the output of that process to actually affect the
182+
// downstream code in Webpack we would still need to mutate the original
183+
// ResolveData with the results (primarily the `createData`). So since we
184+
// cannot avoid the mutation anyway, it seems best to do it earlier rather
185+
// than later, so that everything from here forward is "normal".
186+
//
187+
// Technically a NormalModuleLoader `resolve` hook *can* directly return a
188+
// Module, but that is not how the stock one works, and it would force us to
189+
// copy more of Webpack's default behaviors into the inside of our hook. Like,
190+
// we would need to invoke afterResolve, createModule, createModuleClass, etc,
191+
// just like webpack does if we wanted to produce a Module directly.
192+
//
193+
// So the mutation strategy is much less intrusive, even though it means there
194+
// is the risk of state leakage all over the place.
195+
//
196+
// We mitigate that risk by waiting until the last possible moment to apply
197+
// our desired ModuleRequest fields to the ResolveData. This means that as
198+
// requests evolve through the module-resolver they aren't actually all
199+
// mutating the shared state. Only when a request is allowed to bubble back
200+
// out to webpack does that happen.
179201
toWebpackResolveData(): ExtendedResolveData {
180202
this.originalState.request = this.specifier;
181203
this.originalState.context = dirname(this.fromFile);

0 commit comments

Comments
 (0)