diff --git a/packages/metro-config/src/configTypes.flow.js b/packages/metro-config/src/configTypes.flow.js index 6832e52862..05bf760046 100644 --- a/packages/metro-config/src/configTypes.flow.js +++ b/packages/metro-config/src/configTypes.flow.js @@ -120,7 +120,7 @@ type ResolverConfigT = { }; type SerializerConfigT = { - createModuleIdFactory: () => (path: string) => number, + createModuleIdFactory: () => (path: string) => number | string, customSerializer: ?( entryPoint: string, preModules: $ReadOnlyArray>, diff --git a/packages/metro-config/types/configTypes.d.ts b/packages/metro-config/types/configTypes.d.ts index 2dc65b821d..57fa5e01b6 100644 --- a/packages/metro-config/types/configTypes.d.ts +++ b/packages/metro-config/types/configTypes.d.ts @@ -115,7 +115,7 @@ export interface ResolverConfigT { } export interface SerializerConfigT { - createModuleIdFactory: () => (path: string) => number; + createModuleIdFactory: () => (path: string) => number | string; customSerializer: | (( entryPoint: string, diff --git a/packages/metro-runtime/src/polyfills/require.js b/packages/metro-runtime/src/polyfills/require.js index cd3b1db8af..e80e3441a3 100644 --- a/packages/metro-runtime/src/polyfills/require.js +++ b/packages/metro-runtime/src/polyfills/require.js @@ -47,7 +47,7 @@ type HotModuleReloadingData = { accept: (callback?: HotModuleReloadingCallback) => void, dispose: (callback?: HotModuleReloadingCallback) => void, }; -type ModuleID = number; +type ModuleID = number | string; type Module = { id?: ModuleID, exports: Exports, @@ -67,15 +67,11 @@ type ModuleDefinition = { publicModule: Module, verboseName?: string, }; -type ModuleList = { - [number]: ?ModuleDefinition, - __proto__: null, - ... -}; +type ModuleList = Map; export type RequireFn = (id: ModuleID | VerboseModuleNameForDev) => Exports; export type DefineFn = ( factory: FactoryFn, - moduleId: number, + moduleId: ModuleID, dependencyMap?: DependencyMap, verboseName?: string, inverseDependencies?: InverseDependencyMap, @@ -103,7 +99,7 @@ if (__DEV__) { } function clear(): ModuleList { - modules = (Object.create(null): ModuleList); + modules = (new Map(): ModuleList); // We return modules here so that we can assign an initial value to modules // when defining it. Otherwise, we would have to do "let modules = null", @@ -112,20 +108,15 @@ function clear(): ModuleList { } if (__DEV__) { - var verboseNamesToModuleIds: { - [key: string]: number, - __proto__: null, - ... - } = Object.create(null); - var initializingModuleIds: Array = []; + var initializingModuleIds: Array = []; } function define( factory: FactoryFn, - moduleId: number, + moduleId: ModuleID, dependencyMap?: DependencyMap, ): void { - if (modules[moduleId] != null) { + if (modules.has(moduleId)) { if (__DEV__) { // (We take `inverseDependencies` from `arguments` to avoid an unused // named parameter in `define` in production. @@ -153,7 +144,7 @@ function define( publicModule: {exports: {}}, }; - modules[moduleId] = mod; + modules.set(moduleId, mod); if (__DEV__) { // HMR @@ -165,37 +156,18 @@ function define( const verboseName: string | void = arguments[3]; if (verboseName) { mod.verboseName = verboseName; - verboseNamesToModuleIds[verboseName] = moduleId; } } } function metroRequire(moduleId: ModuleID | VerboseModuleNameForDev): Exports { - if (__DEV__ && typeof moduleId === 'string') { - const verboseName = moduleId; - moduleId = verboseNamesToModuleIds[verboseName]; - 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!', - ); - } - } - - //$FlowFixMe: at this point we know that moduleId is a number - const moduleIdReallyIsNumber: number = moduleId; - if (__DEV__) { - const initializingIndex = initializingModuleIds.indexOf( - moduleIdReallyIsNumber, - ); + const initializingIndex = initializingModuleIds.indexOf(moduleId); if (initializingIndex !== -1) { const cycle = initializingModuleIds .slice(initializingIndex) - .map((id: number) => - modules[id] ? modules[id].verboseName : '[unknown]', + .map((id: ModuleID) => + modules.has(id) ? modules.get(id).verboseName : '[unknown]', ); if (shouldPrintRequireCycle(cycle)) { @@ -209,11 +181,11 @@ function metroRequire(moduleId: ModuleID | VerboseModuleNameForDev): Exports { } } - const module = modules[moduleIdReallyIsNumber]; + const module = modules.get(moduleId); return module && module.isInitialized ? module.publicModule.exports - : guardedLoadModule(moduleIdReallyIsNumber, module); + : guardedLoadModule(moduleId, module); } // We print require cycles unless they match a pattern in the @@ -235,49 +207,30 @@ function shouldPrintRequireCycle(modules: $ReadOnlyArray): boolean { function metroImportDefault( moduleId: ModuleID | VerboseModuleNameForDev, ): any | Exports { - if (__DEV__ && typeof moduleId === 'string') { - const verboseName = moduleId; - moduleId = verboseNamesToModuleIds[verboseName]; - } - - //$FlowFixMe: at this point we know that moduleId is a number - const moduleIdReallyIsNumber: number = moduleId; - if ( - modules[moduleIdReallyIsNumber] && - modules[moduleIdReallyIsNumber].importedDefault !== EMPTY + modules.has(moduleId) && + modules.get(moduleId).importedDefault !== EMPTY ) { - return modules[moduleIdReallyIsNumber].importedDefault; + return modules.get(moduleId).importedDefault; } - const exports: Exports = metroRequire(moduleIdReallyIsNumber); + const exports: Exports = metroRequire(moduleId); const importedDefault: any | Exports = exports && exports.__esModule ? exports.default : exports; - // $FlowFixMe The metroRequire call above will throw if modules[id] is null - return (modules[moduleIdReallyIsNumber].importedDefault = importedDefault); + // $FlowFixMe The metroRequire call above will throw if modules.get(id) is null + return (modules.get(moduleId).importedDefault = importedDefault); } metroRequire.importDefault = metroImportDefault; function metroImportAll( - moduleId: ModuleID | VerboseModuleNameForDev | number, + moduleId: ModuleID | VerboseModuleNameForDev, ): any | Exports | {[string]: any} { - if (__DEV__ && typeof moduleId === 'string') { - const verboseName = moduleId; - moduleId = verboseNamesToModuleIds[verboseName]; - } - - //$FlowFixMe: at this point we know that moduleId is a number - const moduleIdReallyIsNumber: number = moduleId; - - if ( - modules[moduleIdReallyIsNumber] && - modules[moduleIdReallyIsNumber].importedAll !== EMPTY - ) { - return modules[moduleIdReallyIsNumber].importedAll; + if (modules.has(moduleId) && modules.get(moduleId).importedAll !== EMPTY) { + return modules.get(moduleId).importedAll; } - const exports: Exports = metroRequire(moduleIdReallyIsNumber); + const exports: Exports = metroRequire(moduleId); let importedAll: Exports | {[string]: any}; if (exports && exports.__esModule) { @@ -297,8 +250,8 @@ function metroImportAll( importedAll.default = exports; } - // $FlowFixMe The metroRequire call above will throw if modules[id] is null - return (modules[moduleIdReallyIsNumber].importedAll = importedAll); + // $FlowFixMe The metroRequire call above will throw if modules.get(id) is null + return (modules.get(moduleId).importedAll = importedAll); } metroRequire.importAll = metroImportAll; @@ -394,7 +347,7 @@ function registerSegment( } if (moduleIds) { moduleIds.forEach(moduleId => { - if (!modules[moduleId] && !definingSegmentByModuleID.has(moduleId)) { + if (!modules.has(moduleId) && !definingSegmentByModuleID.has(moduleId)) { definingSegmentByModuleID.set(moduleId, segmentId); } }); @@ -410,7 +363,7 @@ function loadModuleImplementation( const definer = moduleDefinersBySegmentID[segmentId]; if (definer != null) { definer(moduleId); - module = modules[moduleId]; + module = modules.get(moduleId); definingSegmentByModuleID.delete(moduleId); } } @@ -419,7 +372,7 @@ function loadModuleImplementation( if (!module && nativeRequire) { const {segmentId, localId} = unpackModuleId(moduleId); nativeRequire(localId, segmentId); - module = modules[moduleId]; + module = modules.get(moduleId); } if (!module) { @@ -563,7 +516,7 @@ if (__DEV__) { dependencyMap: DependencyMap, inverseDependencies: InverseDependencyMap, ) { - const mod = modules[id]; + const mod = modules.get(id); if (!mod) { if (factory) { // New modules are going to be handled by the define() method. @@ -606,7 +559,7 @@ if (__DEV__) { updatedModuleIDs = topologicalSort( [id], // Start with the changed module and go upwards pendingID => { - const pendingModule = modules[pendingID]; + const pendingModule = modules.get(pendingID); if (pendingModule == null) { // Nothing to do. return []; @@ -677,7 +630,7 @@ if (__DEV__) { } seenModuleIDs.add(updatedID); - const updatedMod = modules[updatedID]; + const updatedMod = modules.get(updatedID); if (updatedMod == null) { throw new Error('[Refresh] Expected to find the updated module.'); } @@ -734,7 +687,7 @@ if (__DEV__) { // Schedule all parent refresh boundaries to re-run in this loop. for (let j = 0; j < parentIDs.length; j++) { const parentID = parentIDs[j]; - const parentMod = modules[parentID]; + const parentMod = modules.get(parentID); if (parentMod == null) { throw new Error('[Refresh] Expected to find parent module.'); } @@ -810,7 +763,7 @@ if (__DEV__) { factory?: FactoryFn, dependencyMap?: DependencyMap, ): boolean { - const mod = modules[id]; + const mod = modules.get(id); if (mod == null) { throw new Error('[Refresh] Expected to find the module.'); } diff --git a/packages/metro/src/DeltaBundler/Serializers/hmrJSBundle.js b/packages/metro/src/DeltaBundler/Serializers/hmrJSBundle.js index 0e1d45666b..a1f0669fc8 100644 --- a/packages/metro/src/DeltaBundler/Serializers/hmrJSBundle.js +++ b/packages/metro/src/DeltaBundler/Serializers/hmrJSBundle.js @@ -23,7 +23,7 @@ const url = require('url'); type Options = $ReadOnly<{ clientUrl: EntryPointURL, - createModuleId: string => number, + createModuleId: string => number | string, includeAsyncPaths: boolean, projectRoot: string, serverRoot: string, diff --git a/packages/metro/src/HmrServer.js b/packages/metro/src/HmrServer.js index 94969cba51..870c77d545 100644 --- a/packages/metro/src/HmrServer.js +++ b/packages/metro/src/HmrServer.js @@ -69,12 +69,12 @@ function send(sendFns: Array<(string) => void>, message: HmrMessage): void { class HmrServer { _config: ConfigT; _bundler: IncrementalBundler; - _createModuleId: (path: string) => number; + _createModuleId: (path: string) => number | string; _clientGroups: Map; constructor( bundler: IncrementalBundler, - createModuleId: (path: string) => number, + createModuleId: (path: string) => number | string, config: ConfigT, ) { this._config = config; diff --git a/packages/metro/src/Server.js b/packages/metro/src/Server.js index a001ccb46e..a318a1df9b 100644 --- a/packages/metro/src/Server.js +++ b/packages/metro/src/Server.js @@ -134,7 +134,7 @@ const FILES_CHANGED_COUNT_HEADER = 'X-Metro-Files-Changed-Count'; class Server { _bundler: IncrementalBundler; _config: ConfigT; - _createModuleId: (path: string) => number; + _createModuleId: (path: string) => number | string; _isEnded: boolean; _logger: typeof Logger; _nextBundleBuildNumber: number; diff --git a/packages/metro/src/lib/createModuleIdFactory.js b/packages/metro/src/lib/createModuleIdFactory.js index 24e964fe04..aaeef40d87 100644 --- a/packages/metro/src/lib/createModuleIdFactory.js +++ b/packages/metro/src/lib/createModuleIdFactory.js @@ -11,7 +11,7 @@ 'use strict'; -function createModuleIdFactory(): (path: string) => number { +function createModuleIdFactory(): (path: string) => number | string { const fileToIdMap: Map = new Map(); let nextId = 0; return (path: string) => { diff --git a/packages/metro/src/shared/types.flow.js b/packages/metro/src/shared/types.flow.js index 2d4fd618b8..f25b471b59 100644 --- a/packages/metro/src/shared/types.flow.js +++ b/packages/metro/src/shared/types.flow.js @@ -59,7 +59,7 @@ export type BundleOptions = { +shallow: boolean, sourceMapUrl: ?string, sourceUrl: ?string, - createModuleIdFactory?: () => (path: string) => number, + createModuleIdFactory?: () => (path: string) => number | string, +unstable_transformProfile: TransformProfile, }; @@ -137,7 +137,7 @@ export type RequestOptions = { dev?: boolean, minify: boolean, platform: string, - createModuleIdFactory?: () => (path: string) => number, + createModuleIdFactory?: () => (path: string) => number | string, onProgress?: (transformedFileCount: number, totalFileCount: number) => void, +customResolverOptions?: CustomResolverOptions, +customTransformOptions?: CustomTransformOptions, diff --git a/packages/metro/types/shared/types.d.ts b/packages/metro/types/shared/types.d.ts index 0430652453..dc991c1796 100644 --- a/packages/metro/types/shared/types.d.ts +++ b/packages/metro/types/shared/types.d.ts @@ -56,7 +56,7 @@ export interface BundleOptions { readonly shallow: boolean; sourceMapUrl?: string; sourceUrl?: string; - createModuleIdFactory?: () => (path: string) => number; + createModuleIdFactory?: () => (path: string) => number | string; readonly unstable_transformProfile: TransformProfile; } @@ -133,7 +133,7 @@ export interface RequestOptions { dev?: boolean; minify: boolean; platform: string; - createModuleIdFactory?: () => (path: string) => number; + createModuleIdFactory?: () => (path: string) => number | string; onProgress?: (transformedFileCount: number, totalFileCount: number) => void; }