Skip to content

Commit 7ab93df

Browse files
committed
feat: override params in beforeResolve()
1 parent c20ccb2 commit 7ab93df

File tree

2 files changed

+244
-67
lines changed

2 files changed

+244
-67
lines changed

packages/repack/src/modules/ScriptManager/ScriptManager.ts

+107-58
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// biome-ignore lint/style/useNodejsImportProtocol: use 'events' module instead of node builtin
22
import EventEmitter from 'events';
3-
import { AsyncSeriesHook } from 'tapable';
3+
import { AsyncSeriesHook, AsyncSeriesWaterfallHook } from 'tapable';
44
import NativeScriptManager, {
55
type NormalizedScriptLocator,
66
} from './NativeScriptManager.js';
@@ -55,12 +55,6 @@ export interface ResolverOptions {
5555
key?: string;
5656
}
5757

58-
interface ScriptHookParams {
59-
scriptId: string;
60-
caller?: string;
61-
error?: Error;
62-
}
63-
6458
/**
6559
* A manager to ease resolution, downloading and executing additional code from:
6660
* - arbitrary JavaScript scripts
@@ -114,15 +108,49 @@ interface ScriptHookParams {
114108
* ```
115109
*/
116110
export class ScriptManager extends EventEmitter {
117-
hooks: {
118-
beforeResolve: AsyncSeriesHook<[ScriptHookParams]>;
119-
resolve: AsyncSeriesHook<[ScriptHookParams]>;
120-
afterResolve: AsyncSeriesHook<[ScriptHookParams]>;
121-
errorResolve: AsyncSeriesHook<[ScriptHookParams]>;
122-
beforeLoad: AsyncSeriesHook<[ScriptHookParams]>;
123-
load: AsyncSeriesHook<[ScriptHookParams]>;
124-
afterLoad: AsyncSeriesHook<[ScriptHookParams]>;
125-
errorLoad: AsyncSeriesHook<[ScriptHookParams]>;
111+
private resolvers: Array<[string, string | number, ScriptLocatorResolver]> =
112+
[];
113+
protected cache: Cache = {};
114+
private storage?: StorageApi;
115+
116+
public hooks = {
117+
beforeResolve: new AsyncSeriesWaterfallHook<{
118+
scriptId: string;
119+
caller?: string;
120+
}>(['params']),
121+
resolve: new AsyncSeriesHook<{ scriptId: string; caller?: string }, void>([
122+
'params',
123+
]),
124+
afterResolve: new AsyncSeriesHook<
125+
{ scriptId: string; caller?: string },
126+
void
127+
>(['params']),
128+
errorResolve: new AsyncSeriesHook<
129+
{
130+
scriptId: string;
131+
caller?: string;
132+
error: Error;
133+
},
134+
void
135+
>(['params']),
136+
beforeLoad: new AsyncSeriesHook<
137+
{ scriptId: string; caller?: string },
138+
void
139+
>(['params']),
140+
load: new AsyncSeriesHook<{ scriptId: string; caller?: string }, void>([
141+
'params',
142+
]),
143+
afterLoad: new AsyncSeriesHook<{ scriptId: string; caller?: string }, void>(
144+
['params']
145+
),
146+
errorLoad: new AsyncSeriesHook<
147+
{
148+
scriptId: string;
149+
caller?: string;
150+
error: Error;
151+
},
152+
void
153+
>(['params']),
126154
};
127155

128156
static init() {
@@ -135,11 +163,8 @@ export class ScriptManager extends EventEmitter {
135163
return __webpack_require__.repack.shared.scriptManager!;
136164
}
137165

138-
protected cache: Cache = {};
139166
protected scriptsPromises: ScriptsPromises = {};
140167
protected cacheInitialized = false;
141-
protected resolvers: [string, number, ScriptLocatorResolver][] = [];
142-
protected storage?: StorageApi;
143168

144169
/**
145170
* Constructs instance of `ScriptManager`.
@@ -164,17 +189,6 @@ export class ScriptManager extends EventEmitter {
164189
);
165190
}
166191

167-
this.hooks = {
168-
beforeResolve: new AsyncSeriesHook<[ScriptHookParams]>(['params']),
169-
resolve: new AsyncSeriesHook<[ScriptHookParams]>(['params']),
170-
afterResolve: new AsyncSeriesHook<[ScriptHookParams]>(['params']),
171-
errorResolve: new AsyncSeriesHook<[ScriptHookParams]>(['params']),
172-
beforeLoad: new AsyncSeriesHook<[ScriptHookParams]>(['params']),
173-
load: new AsyncSeriesHook<[ScriptHookParams]>(['params']),
174-
afterLoad: new AsyncSeriesHook<[ScriptHookParams]>(['params']),
175-
errorLoad: new AsyncSeriesHook<[ScriptHookParams]>(['params']),
176-
};
177-
178192
__webpack_require__.repack.shared.scriptManager = this;
179193
}
180194

@@ -213,7 +227,7 @@ export class ScriptManager extends EventEmitter {
213227
this.resolvers = this.resolvers
214228
.filter(([key]) => key !== uniqueKey)
215229
.concat([[uniqueKey ?? DEFAULT_RESOLVER_KEY, priority, resolver]])
216-
.sort(([, a], [, b]) => b - a);
230+
.sort(([, a], [, b]) => Number(b) - Number(a));
217231
}
218232

219233
/**
@@ -283,41 +297,67 @@ export class ScriptManager extends EventEmitter {
283297
webpackContext = getWebpackContext(),
284298
referenceUrl?: string
285299
): Promise<Script> {
286-
await this.initCache();
300+
let finalScriptId = scriptId;
301+
let finalCaller = caller;
302+
287303
try {
304+
await this.initCache();
305+
288306
if (!this.resolvers.length) {
289-
throw new Error(
307+
const error = new Error(
290308
'No script resolvers were added. Did you forget to call `ScriptManager.shared.addResolver(...)`?'
291309
);
310+
await this.hooks.errorResolve.promise({
311+
scriptId: finalScriptId,
312+
caller: finalCaller,
313+
error,
314+
});
315+
throw error;
292316
}
293317

294-
await this.hooks.beforeResolve.promise({ scriptId, caller });
295-
this.emit('resolving', { scriptId, caller });
318+
const hookResult = await this.hooks.beforeResolve.promise({
319+
scriptId,
320+
caller,
321+
});
322+
323+
if (hookResult) {
324+
finalScriptId = hookResult.scriptId;
325+
finalCaller = hookResult.caller;
326+
}
327+
328+
this.emit('resolving', { scriptId: finalScriptId, caller: finalCaller });
296329

297330
// Check if there are any taps in the resolve hook
298331
const _hasResolveHooks = this.hooks.resolve.taps.length > 0;
299332

300333
let locator: ScriptLocator | undefined;
301334

302335
// if (hasResolveHooks) {
303-
await this.hooks.resolve.promise({ scriptId, caller });
336+
await this.hooks.resolve.promise({
337+
scriptId: finalScriptId,
338+
caller: finalCaller,
339+
});
304340
// } else {
305341
for (const [, , resolve] of this.resolvers) {
306-
const resolvedLocator = await resolve(scriptId, caller, referenceUrl);
342+
const resolvedLocator = await resolve(
343+
finalScriptId,
344+
finalCaller,
345+
referenceUrl
346+
);
307347
if (resolvedLocator) {
308348
locator = resolvedLocator;
309349
break;
310350
}
351+
// }
311352
}
312-
// }
313353

314354
if (!locator) {
315355
const error = new Error(
316-
`No resolver was able to resolve script ${scriptId}`
356+
`No resolver was able to resolve script ${finalScriptId}`
317357
);
318358
await this.hooks.errorResolve.promise({
319-
scriptId,
320-
caller,
359+
scriptId: finalScriptId,
360+
caller: finalCaller,
321361
error,
322362
});
323363
throw error;
@@ -327,15 +367,19 @@ export class ScriptManager extends EventEmitter {
327367
locator.url = locator.url(webpackContext);
328368
}
329369

330-
const script = Script.from({ scriptId, caller }, locator, false);
370+
const script = Script.from(
371+
{ scriptId: finalScriptId, caller: finalCaller },
372+
locator,
373+
false
374+
);
331375
const cacheKey = script.locator.uniqueId;
332376

333377
// Check if user provided a custom shouldUpdateScript function
334378
if (locator.shouldUpdateScript) {
335379
// If so, we need to wait for it to resolve
336380
const fetch = await locator.shouldUpdateScript(
337-
scriptId,
338-
caller,
381+
finalScriptId,
382+
finalCaller,
339383
script.shouldUpdateCache(this.cache[cacheKey])
340384
);
341385

@@ -344,7 +388,7 @@ export class ScriptManager extends EventEmitter {
344388
script.locator.fetch = true;
345389
}
346390

347-
await this.hooks.resolve.promise({ scriptId, caller });
391+
// await this.hooks.resolve.promise({ scriptId: finalScriptId, caller: finalCaller });
348392
this.emit('resolved', script.toObject());
349393

350394
// if it returns false, we don't need to fetch the script
@@ -358,24 +402,23 @@ export class ScriptManager extends EventEmitter {
358402
script.locator.fetch = true;
359403
}
360404

361-
// Only call resolve hook if it wasn't called during resolution
362-
// if (!hasResolveHooks) {
363-
await this.hooks.resolve.promise({ scriptId, caller });
364-
// }
365-
await this.hooks.afterResolve.promise({ scriptId, caller });
405+
await this.hooks.afterResolve.promise({
406+
scriptId: finalScriptId,
407+
caller: finalCaller,
408+
});
366409
this.emit('resolved', script.toObject());
367410

368411
return script;
369412
} catch (error) {
370413
await this.hooks.errorResolve.promise({
371-
scriptId,
372-
caller,
414+
scriptId: finalScriptId,
415+
caller: finalCaller,
373416
error: error as Error,
374417
});
375418
this.handleError(
376419
error,
377420
'[ScriptManager] Failed while resolving script locator:',
378-
{ scriptId, caller }
421+
{ scriptId: finalScriptId, caller: finalCaller }
379422
);
380423
}
381424
}
@@ -427,24 +470,30 @@ export class ScriptManager extends EventEmitter {
427470
);
428471

429472
try {
430-
await this.hooks.beforeLoad.promise({ scriptId, caller });
473+
await this.hooks.beforeLoad.promise({
474+
scriptId: scriptId,
475+
caller: caller,
476+
});
431477
this.emit('loading', script.toObject());
432478

433479
const _hasLoadHooks = this.hooks.load.taps.length > 0;
434480
// if (hasLoadHooks) {
435-
await this.hooks.load.promise({ scriptId, caller });
481+
await this.hooks.load.promise({ scriptId: scriptId, caller: caller });
436482
// } else {
437483
await this.loadScriptWithRetry(scriptId, script.locator);
438484
// }
439485

440-
await this.hooks.afterLoad.promise({ scriptId, caller });
486+
await this.hooks.afterLoad.promise({
487+
scriptId: scriptId,
488+
caller: caller,
489+
});
441490
this.emit('loaded', script.toObject());
442491
await this.updateCache(script);
443492
} catch (error) {
444493
const { code } = error as Error & { code: string };
445494
await this.hooks.errorLoad.promise({
446-
scriptId,
447-
caller,
495+
scriptId: scriptId,
496+
caller: caller,
448497
error: error as Error,
449498
});
450499
this.handleError(

0 commit comments

Comments
 (0)