Skip to content

Commit

Permalink
Implement caching in __loadBundleAsync (#36809)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #36809

Changelog: [General][Added] [2/n] Support lazy bundling in development

Implements caching in `__loadBundleAsync` in line with react-native-community/discussions-and-proposals#628.

Reviewed By: jacdebug

Differential Revision: D44630077

fbshipit-source-id: f1a19217f54493e5cf0c8bba910a6a6e14c10c03
  • Loading branch information
motiz88 authored and pull[bot] committed Dec 31, 2023
1 parent fb21714 commit 082054a
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,46 @@ test('shows and hides the loading view around concurrent requests', async () =>
await promise2;
expect(loadingViewMock.hide).toHaveBeenCalledTimes(1);
});

test('loadBundleFromServer does not cache errors', async () => {
mockHeaders = {'Content-Type': 'application/json'};
mockDataResponse = JSON.stringify({message: 'Error thrown from Metro'});

await expect(
loadBundleFromServer('/Fail.bundle?platform=ios'),
).rejects.toThrow();

mockDataResponse = '"code";';
mockHeaders = {'Content-Type': 'application/javascript'};

await expect(
loadBundleFromServer('/Fail.bundle?platform=ios'),
).resolves.not.toThrow();
});

test('loadBundleFromServer caches successful fetches', async () => {
mockDataResponse = '"code";';
mockHeaders = {'Content-Type': 'application/javascript'};

const promise1 = loadBundleFromServer(
'/Banana.bundle?platform=ios&dev=true&minify=false&unusedExtraParam=42&modulesOnly=true&runModule=false',
);

// Request again in the same tick = same promise
const promise2 = loadBundleFromServer(
'/Banana.bundle?platform=ios&dev=true&minify=false&unusedExtraParam=42&modulesOnly=true&runModule=false',
);
expect(promise2).toBe(promise1);

await promise1;

// Request again once resolved = still the same promise
const promise3 = loadBundleFromServer(
'/Banana.bundle?platform=ios&dev=true&minify=false&unusedExtraParam=42&modulesOnly=true&runModule=false',
);
expect(promise3).toBe(promise1);

await promise2;

expect(sendRequest).toBeCalledTimes(1);
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ declare var global: {globalEvalWithSourceUrl?: (string, string) => mixed, ...};

let pendingRequests = 0;

const cachedPromisesByUrl = new Map<string, Promise<void>>();

function asyncRequest(
url: string,
): Promise<{body: string, headers: {[string]: string}}> {
Expand Down Expand Up @@ -90,9 +92,15 @@ function buildUrlForBundle(bundlePathAndQuery: string) {
module.exports = function (bundlePathAndQuery: string): Promise<void> {
const requestUrl = buildUrlForBundle(bundlePathAndQuery);

let loadPromise = cachedPromisesByUrl.get(requestUrl);

if (loadPromise) {
return loadPromise;
}
LoadingView.showMessage('Downloading...', 'load');
++pendingRequests;
return asyncRequest(requestUrl)

loadPromise = asyncRequest(requestUrl)
.then<void>(({body, headers}) => {
if (
headers['Content-Type'] != null &&
Expand All @@ -116,9 +124,16 @@ module.exports = function (bundlePathAndQuery: string): Promise<void> {
eval(body);
}
})
.catch<void>(e => {
cachedPromisesByUrl.delete(requestUrl);
throw e;
})
.finally(() => {
if (!--pendingRequests) {
LoadingView.hide();
}
});

cachedPromisesByUrl.set(requestUrl, loadPromise);
return loadPromise;
};

0 comments on commit 082054a

Please sign in to comment.