Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: initial version of ScriptManager tapable hooks #1078

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Prev Previous commit
feat: add an ability to replace load and resolve
szymonrybczak committed Mar 19, 2025
commit 8040efab95314d72e5a46dc818af57a311d6cfec
40 changes: 32 additions & 8 deletions apps/tester-app/index.js
Original file line number Diff line number Diff line change
@@ -69,12 +69,27 @@ ScriptManager.shared.hooks.beforeResolve.tapAsync(

ScriptManager.shared.hooks.resolve.tapAsync(
'test-during',
({ scriptId, caller, error }, callback) => {
if (!error) {
console.log('During resolving:', scriptId, caller);
async (params, callback) => {
try {
for (const [, , resolve] of params.resolvers) {
const resolvedLocator = await resolve(
params.scriptId,
params.caller,
params.referenceUrl
);
if (resolvedLocator) {
callback(null, {
...params,
result: resolvedLocator,
});
}
}
// If no resolver found a result, pass through the params unchanged
callback(null, params);
} catch (error) {
console.error('Error resolving:', error);
callback(error);
}
console.log('ScriptManager.shared.hooks.resolve', scriptId, caller, error);
callback();
}
);

@@ -125,9 +140,18 @@ ScriptManager.shared.hooks.beforeLoad.tapAsync(

ScriptManager.shared.hooks.load.tapAsync(
'test-load',
({ scriptId, caller, error }, callback) => {
console.log('ScriptManager.shared.hooks.load', scriptId, caller, error);
callback();
async (params, callback) => {
try {
console.log(
'ScriptManager.shared.hooks.load',
params.scriptId,
params.caller
);
await params.loadScript();
callback(null);
} catch (error) {
callback(error);
}
}
);

92 changes: 61 additions & 31 deletions packages/repack/src/modules/ScriptManager/ScriptManager.ts
Original file line number Diff line number Diff line change
@@ -55,6 +55,22 @@ export interface ResolverOptions {
key?: string;
}

interface ResolveHookParams {
scriptId: string;
caller?: string;
referenceUrl?: string;
resolvers: Array<[string, string | number, ScriptLocatorResolver]>;
result?: ScriptLocator;
}

interface LoadHookParams {
scriptId: string;
caller?: string;
locator: NormalizedScriptLocator;
loadScript: () => Promise<void>;
handled?: boolean;
}

/**
* A manager to ease resolution, downloading and executing additional code from:
* - arbitrary JavaScript scripts
@@ -118,9 +134,7 @@ export class ScriptManager extends EventEmitter {
scriptId: string;
caller?: string;
}>(['params']),
resolve: new AsyncSeriesHook<{ scriptId: string; caller?: string }, void>([
'params',
]),
resolve: new AsyncSeriesWaterfallHook<ResolveHookParams>(['params']),
afterResolve: new AsyncSeriesHook<
{ scriptId: string; caller?: string },
void
@@ -137,9 +151,7 @@ export class ScriptManager extends EventEmitter {
{ scriptId: string; caller?: string },
void
>(['params']),
load: new AsyncSeriesHook<{ scriptId: string; caller?: string }, void>([
'params',
]),
load: new AsyncSeriesWaterfallHook<LoadHookParams>(['params']),
afterLoad: new AsyncSeriesHook<{ scriptId: string; caller?: string }, void>(
['params']
),
@@ -326,29 +338,32 @@ export class ScriptManager extends EventEmitter {
}

this.emit('resolving', { scriptId: finalScriptId, caller: finalCaller });

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

let locator: ScriptLocator | undefined;

// if (hasResolveHooks) {
await this.hooks.resolve.promise({
scriptId: finalScriptId,
caller: finalCaller,
});
// } else {
for (const [, , resolve] of this.resolvers) {
const resolvedLocator = await resolve(
finalScriptId,
finalCaller,
referenceUrl
);
if (resolvedLocator) {
locator = resolvedLocator;
break;
if (hasResolveHooks) {
const params = await this.hooks.resolve.promise({
scriptId: finalScriptId,
caller: finalCaller,
referenceUrl,
resolvers: this.resolvers,
});

locator = params.result;
} else {
for (const [, , resolve] of this.resolvers) {
const resolvedLocator = await resolve(
finalScriptId,
finalCaller,
referenceUrl
);
if (resolvedLocator) {
locator = resolvedLocator;
break;
}
}
// }
}

if (!locator) {
@@ -476,12 +491,27 @@ export class ScriptManager extends EventEmitter {
});
this.emit('loading', script.toObject());

const _hasLoadHooks = this.hooks.load.taps.length > 0;
// if (hasLoadHooks) {
await this.hooks.load.promise({ scriptId: scriptId, caller: caller });
// } else {
await this.loadScriptWithRetry(scriptId, script.locator);
// }
const hasLoadHooks =
this.hooks.load.taps && this.hooks.load.taps.length > 0;

if (hasLoadHooks) {
await this.hooks.load.promise({
scriptId,
caller,
locator: script.locator,
loadScript: async () => {
await this.loadScriptWithRetry(scriptId, script.locator);
},
});

// If the hook didn't handle loading, use default loading
// FIXME: Not sure if that's needed.
// if (!params.handled) {
// await this.loadScriptWithRetry(scriptId, script.locator);
// }
} else {
await this.loadScriptWithRetry(scriptId, script.locator);
}

await this.hooks.afterLoad.promise({
scriptId: scriptId,
Loading