Skip to content

Commit

Permalink
metro: introduce asyncRequire function
Browse files Browse the repository at this point in the history
Reviewed By: davidaurelio

Differential Revision: D6498107

fbshipit-source-id: a9c4ab634e60f19b7058205eddcd248f57f63500
  • Loading branch information
Jean Lauliac authored and facebook-github-bot committed Dec 7, 2017
1 parent 3d5dc87 commit a7b231a
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 58 deletions.
58 changes: 0 additions & 58 deletions Libraries/Utilities/BundleSegments.js

This file was deleted.

79 changes: 79 additions & 0 deletions Libraries/Utilities/asyncRequire.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @flow
* @format
* @providesModule asyncRequire
*/

'use strict';

/**
* The bundler must register the dependency properly when generating a call to
* `asyncRequire`, that allows us to call `require` dynamically with confidence
* the module ID is indeed valid and available.
*/
function asyncRequire(moduleID: number): Promise<mixed> {
return Promise.resolve()
.then(() => {
const {segmentId} = (require: $FlowFixMe).unpackModuleId(moduleID);
return loadSegment(segmentId);
})
.then(() => require.call(null, (moduleID: $FlowFixMe)));
}

let segmentLoaders = new Map();

/**
* Ensure that a bundle segment is ready for use, for example requiring some of
* its module. We cache load promises so as to avoid calling `fetchSegment`
* twice for the same bundle. We assume that once a segment is fetched/loaded,
* it is never gettting removed during this instance of the JavaScript VM.
*
* Segment #0 is the main segment, that is always available by definition, so
* we never try to load anything.
*
* We don't use async/await syntax to avoid depending on `regeneratorRuntime`.
*/
function loadSegment(segmentId: number): Promise<void> {
return Promise.resolve().then(() => {
if (segmentId === 0) {
return;
}
let segmentLoader = segmentLoaders.get(segmentId);
if (segmentLoader != null) {
return segmentLoader;
}
const {fetchSegment} = global;
if (fetchSegment == null) {
throw new FetchSegmentNotAvailableError();
}
segmentLoader = new Promise((resolve, reject) => {
fetchSegment(segmentId, error => {
if (error != null) {
reject(error);
return;
}
resolve();
});
});
segmentLoaders.set(segmentId, segmentLoader);
return segmentLoader;
});
}

class FetchSegmentNotAvailableError extends Error {
constructor() {
super(
'When bundle splitting is enabled, the `global.fetchSegment` function ' +
'must be provided to be able to load particular bundle segments.',
);
}
}

module.exports = asyncRequire;

0 comments on commit a7b231a

Please # to comment.