diff --git a/Libraries/Utilities/asyncRequire.js b/Libraries/Utilities/asyncRequire.js index 3a403b8dd91e2a..6f4f2e1ce3f505 100644 --- a/Libraries/Utilities/asyncRequire.js +++ b/Libraries/Utilities/asyncRequire.js @@ -13,6 +13,8 @@ 'use strict'; +const dynamicRequire: number => mixed = (require: $FlowFixMe); + /** * The bundler must register the dependency properly when generating a call to * `asyncRequire`, that allows us to call `require` dynamically with confidence @@ -24,7 +26,7 @@ function asyncRequire(moduleID: number): Promise { const {segmentId} = (require: $FlowFixMe).unpackModuleId(moduleID); return loadSegment(segmentId); }) - .then(() => require.call(null, (moduleID: $FlowFixMe))); + .then(() => dynamicRequire(moduleID)); } let segmentLoaders = new Map(); @@ -45,6 +47,10 @@ function loadSegment(segmentId: number): Promise { if (segmentId === 0) { return; } + if (typeof global.__BUNDLE_DIGEST__ !== 'string') { + throw IncorrectBundleSetupError(); + } + const globalDigest = global.__BUNDLE_DIGEST__; let segmentLoader = segmentLoaders.get(segmentId); if (segmentLoader != null) { return segmentLoader; @@ -61,6 +67,19 @@ function loadSegment(segmentId: number): Promise { } resolve(); }); + }).then(() => { + const metaModuleId = (require: $FlowFixMe).packModuleId({ + segmentId, + localId: 0, + }); + const metaModule = dynamicRequire(metaModuleId); + const digest: string = + typeof metaModule === 'object' && metaModule != null + ? (metaModule.BUNDLE_DIGEST: $FlowFixMe) + : 'undefined'; + if (digest !== globalDigest) { + throw new IncompatibleSegmentError(globalDigest, digest); + } }); segmentLoaders.set(segmentId, segmentLoader); return segmentLoader; @@ -76,4 +95,27 @@ class FetchSegmentNotAvailableError extends Error { } } +class IncorrectBundleSetupError extends Error { + constructor() { + super( + 'To be able to use split segments, the bundler must define a global ' + + 'constant `__BUNDLE_DIGEST__` that identifies the bundle uniquely.', + ); + } +} +asyncRequire.IncorrectBundleSetupError = IncorrectBundleSetupError; + +class IncompatibleSegmentError extends Error { + constructor(globalDigest, segmentDigest) { + super( + 'The split segment that is being loaded has been built from a ' + + 'different version of the code than the main segment. Or, the ' + + 'bundler is setting up the module #0 of the segment incorrectly. ' + + `The global digest is \`${globalDigest}\` while the segment is ` + + `\`${segmentDigest}\`.`, + ); + } +} +asyncRequire.IncompatibleSegmentError = IncompatibleSegmentError; + module.exports = asyncRequire;