diff --git a/react-packager/src/Resolver/polyfills/require.js b/react-packager/src/Resolver/polyfills/require.js index 094bdeff..88fdbb86 100644 --- a/react-packager/src/Resolver/polyfills/require.js +++ b/react-packager/src/Resolver/polyfills/require.js @@ -5,19 +5,54 @@ * 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 */ 'use strict'; +type Exports = any; +type FactoryFn = ( + global: Object, + require: RequireFn, + moduleObject: {exports: {}}, + exports: {}, +) => void; +type HotModuleReloadingAcceptFn = Function; +type HotModuleReloadingData = {| + acceptCallback: ?HotModuleReloadingAcceptFn, + accept: (callback: HotModuleReloadingAcceptFn) => void, +|}; +type Module = { + exports: Exports, + hot?: HotModuleReloadingData, +}; +type ModuleID = number; +type ModuleDefinition = {| + factory: FactoryFn, + hasError: boolean, + isInitialized: boolean, + exports: Exports, + verboseName?: string, + hot?: HotModuleReloadingData, +|}; +type ModuleMap = + {[key: ModuleID]: (ModuleDefinition)}; +type RequireFn = (id: ModuleID | VerboseModuleNameForDev) => Exports; +type VerboseModuleNameForDev = string; + global.require = require; global.__d = define; -const modules = Object.create(null); +const modules: ModuleMap = Object.create(null); if (__DEV__) { - var verboseNamesToModuleIds = Object.create(null); + var verboseNamesToModuleIds: {[key: string]: number} = Object.create(null); } -function define(moduleId, factory) { +function define( + moduleId: number, + factory: FactoryFn, +) { if (moduleId in modules) { // prevent repeated calls to `global.nativeRequire` to overwrite modules // that are already loaded @@ -35,22 +70,38 @@ function define(moduleId, factory) { // DEBUGGABLE MODULES NAMES // avoid unnecessary parameter in prod - const verboseName = modules[moduleId].verboseName = arguments[2]; - verboseNamesToModuleIds[verboseName] = moduleId; + const verboseName: string | void = arguments[2]; + if (verboseName) { + modules[moduleId].verboseName = verboseName; + verboseNamesToModuleIds[verboseName] = moduleId; + } } } -function require(moduleId) { - const module = __DEV__ - ? modules[moduleId] || modules[verboseNamesToModuleIds[moduleId]] - : modules[moduleId]; +function require(moduleId: ModuleID | VerboseModuleNameForDev) { + if (__DEV__ && typeof moduleId === 'string') { + const verboseName = moduleId; + moduleId = verboseNamesToModuleIds[moduleId]; + if (moduleId == null) { + throw new Error(`Unknown named module: '${verboseName}'`); + } else { + console.warn( + `Requiring module '${verboseName}' by name is only supported for ` + + 'debugging purposes and will BREAK IN PRODUCTION!' + ); + } + } else { + moduleId = +moduleId; + } + + const module = modules[moduleId]; return module && module.isInitialized ? module.exports : guardedLoadModule(moduleId, module); } let inGuard = false; -function guardedLoadModule(moduleId, module) { +function guardedLoadModule(moduleId: ModuleID , module) { if (!inGuard && global.ErrorUtils) { inGuard = true; let returnValue; @@ -73,17 +124,6 @@ function loadModuleImplementation(moduleId, module) { module = modules[moduleId]; } - if (__DEV__ && !module) { - // allow verbose module names to be passed as module ID - module = modules[verboseNamesToModuleIds[moduleId]]; - if (module) { - console.warn( - `Requiring module '${moduleId}' by name is only supported for ` + - 'debugging purposes and will break in production' - ); - } - } - if (!module) { throw unknownModuleError(moduleId); } @@ -109,24 +149,28 @@ function loadModuleImplementation(moduleId, module) { const {factory} = module; try { if (__DEV__) { + // $FlowFixMe: we know that __DEV__ is const and `Systrace` exists Systrace.beginEvent('JS_require_' + (module.verboseName || moduleId)); } - const moduleObject = {exports}; + const moduleObject: Module = {exports}; if (__DEV__ && module.hot) { moduleObject.hot = module.hot; } // keep args in sync with with defineModuleCode in // packager/react-packager/src/Resolver/index.js + // and packager/react-packager/src/ModuleGraph/worker.js factory(global, require, moduleObject, exports); // avoid removing factory in DEV mode as it breaks HMR if (!__DEV__) { + // $FlowFixMe: This is only sound because we never access `factory` again module.factory = undefined; } if (__DEV__) { + // $FlowFixMe: we know that __DEV__ is const and `Systrace` exists Systrace.endEvent(); } return (module.exports = moduleObject.exports); @@ -156,14 +200,17 @@ if (__DEV__) { // HOT MODULE RELOADING var createHotReloadingObject = function() { - const hot = { + const hot: HotModuleReloadingData = { acceptCallback: null, accept: callback => { hot.acceptCallback = callback; }, }; return hot; }; - const acceptAll = function(dependentModules, inverseDependencies) { + const acceptAll = function( + dependentModules, + inverseDependencies, + ) { if (!dependentModules || dependentModules.length === 0) { return true; } @@ -178,16 +225,20 @@ if (__DEV__) { return false; } - parents.pushAll(inverseDependencies[notAccepted[i]]); + parents.push(...inverseDependencies[notAccepted[i]]); } return acceptAll(parents, inverseDependencies); }; - const accept = function(id, factory, inverseDependencies) { + const accept = function( + id: ModuleID, + factory?: FactoryFn, + inverseDependencies: {[key: ModuleID]: Array}, + ) { const mod = modules[id]; - if (!mod) { + if (!mod && factory) { // new modules need a factory define(id, factory); return true; // new modules don't need to be accepted }