Skip to content

Commit

Permalink
fix: don't cache failed script
Browse files Browse the repository at this point in the history
  • Loading branch information
hosseinmd committed Oct 18, 2024
1 parent 176324a commit 7a9c81a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 12 deletions.
26 changes: 16 additions & 10 deletions packages/repack/src/modules/ScriptManager/ScriptManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,6 @@ export class ScriptManager extends EventEmitter {
// If it returns true, we need to fetch the script
if (fetch) {
script.locator.fetch = true;
this.cache[cacheKey] = script.getCacheData();
await this.saveCache();
}

this.emit('resolved', script.toObject());
Expand All @@ -288,12 +286,8 @@ export class ScriptManager extends EventEmitter {
// If no custom shouldUpdateScript function was provided, we use the default behaviour
if (!this.cache[cacheKey]) {
script.locator.fetch = true;
this.cache[cacheKey] = script.getCacheData();
await this.saveCache();
} else if (script.shouldRefetch(this.cache[cacheKey])) {
script.locator.fetch = true;
this.cache[cacheKey] = script.getCacheData();
await this.saveCache();
}

this.emit('resolved', script.toObject());
Expand All @@ -308,6 +302,14 @@ export class ScriptManager extends EventEmitter {
}
}

private async updateCache(script: Script) {
if (script.locator.fetch) {
const cacheKey = script.locator.uniqueId;
this.cache[cacheKey] = script.getCacheData();
await this.saveCache();
}
}

/**
* Resolves given script's location, downloads and executes it.
* The execution of the code is handled internally by threading in React Native.
Expand Down Expand Up @@ -344,6 +346,7 @@ export class ScriptManager extends EventEmitter {
this.emit('loading', script.toObject());
await this.loadScriptWithRetry(scriptId, script.locator);
this.emit('loaded', script.toObject());
this.updateCache(script);
} catch (error) {
const { code } = error as Error & { code: string };
this.handleError(
Expand All @@ -352,9 +355,10 @@ export class ScriptManager extends EventEmitter {
code ? `[${code}]` : '',
script.toObject()
);
} finally {
// should delete script promise even script failed
delete this.scriptsPromises[uniqueId];
}

delete this.scriptsPromises[uniqueId];
};

this.scriptsPromises[uniqueId] = loadProcess();
Expand Down Expand Up @@ -424,6 +428,7 @@ export class ScriptManager extends EventEmitter {
try {
this.emit('prefetching', script.toObject());
await this.nativeScriptManager.prefetchScript(scriptId, script.locator);
this.updateCache(script);
} catch (error) {
const { code } = error as Error & { code: string };
this.handleError(
Expand All @@ -432,9 +437,10 @@ export class ScriptManager extends EventEmitter {
code ? `[${code}]` : '',
script.toObject()
);
} finally {
// should delete script promise even script failed
delete this.scriptsPromises[uniqueId];
}

delete this.scriptsPromises[uniqueId];
};

this.scriptsPromises[uniqueId] = loadProcess();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ describe('ScriptManagerAPI', () => {
uniqueId: 'main_src_App_js',
});

await ScriptManager.shared.loadScript('src_App_js', 'main');

const {
locator: { fetch },
} = await ScriptManager.shared.resolveScript('src_App_js', 'main');
Expand Down Expand Up @@ -435,6 +437,7 @@ describe('ScriptManagerAPI', () => {
'src_App_js',
'main'
);
await ScriptManager.shared.loadScript('src_App_js', 'main');
expect(script1.locator.fetch).toBe(false);

ScriptManager.shared.removeAllResolvers();
Expand All @@ -454,6 +457,7 @@ describe('ScriptManagerAPI', () => {
'src_App_js',
'main'
);
await ScriptManager.shared.loadScript('src_App_js', 'main');
expect(script2.locator.fetch).toBe(true);

ScriptManager.shared.removeAllResolvers();
Expand All @@ -473,6 +477,7 @@ describe('ScriptManagerAPI', () => {
'src_App_js',
'main'
);
await ScriptManager.shared.loadScript('src_App_js', 'main');
expect(script3.locator.fetch).toBe(true);

ScriptManager.shared.removeAllResolvers();
Expand All @@ -496,6 +501,7 @@ describe('ScriptManagerAPI', () => {
'src_App_js',
'main'
);
await ScriptManager.shared.loadScript('src_App_js', 'main');
expect(script4.locator.fetch).toBe(true);

ScriptManager.shared.removeAllResolvers();
Expand All @@ -519,6 +525,7 @@ describe('ScriptManagerAPI', () => {
'src_App_js',
'main'
);
await ScriptManager.shared.loadScript('src_App_js', 'main');
expect(script5.locator.fetch).toBe(false);

ScriptManager.shared.removeAllResolvers();
Expand Down Expand Up @@ -590,8 +597,11 @@ describe('ScriptManagerAPI', () => {
expect(NativeScriptManager.loadScript).toHaveBeenCalledTimes(1);
expect(NativeScriptManager.loadScript).toHaveBeenCalledWith(scriptId, {
absolute: false,
fetch: false,
body: undefined,
fetch: true,
headers: undefined,
method: 'GET',
query: undefined,
retry: 2,
retryDelay: 100,
timeout: 30000,
Expand Down Expand Up @@ -646,7 +656,7 @@ describe('ScriptManagerAPI', () => {
expect(NativeScriptManager.loadScript).toHaveBeenCalledTimes(3);
expect(NativeScriptManager.loadScript).toHaveBeenCalledWith(scriptId, {
absolute: false,
fetch: false,
fetch: true,
method: 'GET',
retry: 2,
retryDelay: 100,
Expand Down Expand Up @@ -832,6 +842,43 @@ describe('ScriptManagerAPI', () => {
spy.mockReset();
spy.mockRestore();
});

it('should refetch failed script', async () => {
jest.useFakeTimers({ advanceTimers: true });
const spy = jest.spyOn(NativeScriptManager, 'loadScript');

spy.mockImplementation(
(_scriptId: string, _scriptConfig: NormalizedScriptLocator) =>
Promise.reject({ code: 'NetworkFailed' })
);

const cache = new FakeCache();
ScriptManager.shared.setStorage(cache);

ScriptManager.shared.addResolver(async (scriptId, _caller) => {
return {
url: Script.getRemoteURL(scriptId),
cache: true,
};
});

await expect(async () =>
ScriptManager.shared.loadScript('miniApp')
).rejects.toThrow();

// //expected to cache be empty
expect(Object.keys(cache.data).length).toBe(0);

await expect(async () =>
ScriptManager.shared.loadScript('miniApp')
).rejects.toThrow();

// expected to fetch again
// expect(spy.mock.lastCall?.[1].fetch).toBe(true);

spy.mockReset();
spy.mockRestore();
});
});

function mockLoadScriptBasedOnFetch() {
Expand Down

0 comments on commit 7a9c81a

Please sign in to comment.