From 6e71c2e30a8f50ecc50a4fc334bc86a783a154ac Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Thu, 2 Mar 2017 08:33:04 -0800 Subject: [PATCH] packager: ResolutionRequest: use moduleMap instead of hasteMap Reviewed By: cpojer Differential Revision: D4605535 fbshipit-source-id: bc8394eb296f3fbeda5d8f0f3c17790db8691033 --- .../src/ModuleGraph/node-haste/node-haste.js | 47 ++++++++++++----- .../node-haste/DependencyGraph/HasteMap.js | 2 +- .../DependencyGraph/ResolutionRequest.js | 51 +++++++++++++------ .../src/node-haste/ModuleCache.js | 2 +- .../metro-bundler/src/node-haste/index.js | 16 +++--- 5 files changed, 80 insertions(+), 38 deletions(-) diff --git a/packages/metro-bundler/src/ModuleGraph/node-haste/node-haste.js b/packages/metro-bundler/src/ModuleGraph/node-haste/node-haste.js index f8fa5016..ed23fc82 100644 --- a/packages/metro-bundler/src/ModuleGraph/node-haste/node-haste.js +++ b/packages/metro-bundler/src/ModuleGraph/node-haste/node-haste.js @@ -9,37 +9,55 @@ * @flow */ - 'use strict'; +'use strict'; - import type { // eslint-disable-line sort-requires +import type { // eslint-disable-line sort-requires Extensions, Path, } from './node-haste.flow'; - import type { +import type { ResolveFn, TransformedFile, } from '../types.flow'; - const DependencyGraphHelpers = require('../../node-haste/DependencyGraph/DependencyGraphHelpers'); - const HasteFS = require('./HasteFS'); - const HasteMap = require('../../node-haste/DependencyGraph/HasteMap'); - const Module = require('./Module'); - const ModuleCache = require('./ModuleCache'); - const ResolutionRequest = require('../../node-haste/DependencyGraph/ResolutionRequest'); +const DependencyGraphHelpers = require('../../node-haste/DependencyGraph/DependencyGraphHelpers'); +const HasteFS = require('./HasteFS'); +const HasteMap = require('../../node-haste/DependencyGraph/HasteMap'); +const Module = require('./Module'); +const ModuleCache = require('./ModuleCache'); +const ResolutionRequest = require('../../node-haste/DependencyGraph/ResolutionRequest'); - const defaults = require('../../../defaults'); +const defaults = require('../../../defaults'); - type ResolveOptions = {| +type ResolveOptions = {| assetExts: Extensions, extraNodeModules: {[id: string]: string}, transformedFiles: {[path: Path]: TransformedFile}, |}; - const platforms = new Set(defaults.platforms); +const platforms = new Set(defaults.platforms); - exports.createResolveFn = function(options: ResolveOptions): ResolveFn { - const { +/** + * We don't need to crawl the filesystem all over again so we just mock + * a jest-haste-map's ModuleMap instance. Eventually, though, we'll + * want to figure out how to reunify and get rid of `HasteMap`. + */ +function getFakeModuleMap(hasteMap: HasteMap) { + return { + getModule(name: string, platform_: string): ?string { + const module = hasteMap.getModule(name, platform_); + return module && module.type === 'Module' ? module.path : null; + }, + getPackage(name: string, platform_: string): ?string { + const module = hasteMap.getModule(name, platform_); + return module && module.type === 'Package' ? module.path : null; + }, + }; +} + +exports.createResolveFn = function(options: ResolveOptions): ResolveFn { + const { assetExts, extraNodeModules, transformedFiles, @@ -82,6 +100,7 @@ hasteMap, helpers, moduleCache, + moduleMap: getFakeModuleMap(hasteMap), platform, platforms, preferNativePlatform: true, diff --git a/packages/metro-bundler/src/node-haste/DependencyGraph/HasteMap.js b/packages/metro-bundler/src/node-haste/DependencyGraph/HasteMap.js index d869f17c..0c42f289 100644 --- a/packages/metro-bundler/src/node-haste/DependencyGraph/HasteMap.js +++ b/packages/metro-bundler/src/node-haste/DependencyGraph/HasteMap.js @@ -91,7 +91,7 @@ class HasteMap extends EventEmitter { }); } - getModule(name, platform = null) { + getModule(name, platform = null): Module { const modulesMap = this._map[name]; if (modulesMap == null) { return null; diff --git a/packages/metro-bundler/src/node-haste/DependencyGraph/ResolutionRequest.js b/packages/metro-bundler/src/node-haste/DependencyGraph/ResolutionRequest.js index b59798e6..46583d96 100644 --- a/packages/metro-bundler/src/node-haste/DependencyGraph/ResolutionRequest.js +++ b/packages/metro-bundler/src/node-haste/DependencyGraph/ResolutionRequest.js @@ -17,27 +17,35 @@ const debug = require('debug')('RNP:DependencyGraph'); const util = require('util'); const path = require('path'); const realPath = require('path'); +const invariant = require('fbjs/lib/invariant'); const isAbsolutePath = require('absolute-path'); const getAssetDataFromName = require('../lib/getAssetDataFromName'); import type {HasteFS} from '../types'; import type DependencyGraphHelpers from './DependencyGraphHelpers'; -import type HasteMap from './HasteMap'; import type Module from '../Module'; import type ModuleCache from '../ModuleCache'; import type ResolutionResponse from './ResolutionResponse'; type DirExistsFn = (filePath: string) => boolean; +/** + * `jest-haste-map`'s interface for ModuleMap. + */ +export type ModuleMap = { + getModule(name: string, platform: string, supportsNativePlatform: boolean): ?string, + getPackage(name: string, platform: string, supportsNativePlatform: boolean): ?string, +}; + type Options = { dirExists: DirExistsFn, entryPath: string, extraNodeModules: ?Object, hasteFS: HasteFS, - hasteMap: HasteMap, helpers: DependencyGraphHelpers, // TODO(cpojer): Remove 'any' type. This is used for ModuleGraph/node-haste moduleCache: ModuleCache | any, + moduleMap: ModuleMap, platform: string, platforms: Set, preferNativePlatform: boolean, @@ -48,10 +56,10 @@ class ResolutionRequest { _entryPath: string; _extraNodeModules: ?Object; _hasteFS: HasteFS; - _hasteMap: HasteMap; _helpers: DependencyGraphHelpers; - _immediateResolutionCache: {[key: string]: string}; + _immediateResolutionCache: {[key: string]: Module}; _moduleCache: ModuleCache; + _moduleMap: ModuleMap; _platform: string; _platforms: Set; _preferNativePlatform: boolean; @@ -62,9 +70,9 @@ class ResolutionRequest { entryPath, extraNodeModules, hasteFS, - hasteMap, helpers, moduleCache, + moduleMap, platform, platforms, preferNativePlatform, @@ -73,16 +81,16 @@ class ResolutionRequest { this._entryPath = entryPath; this._extraNodeModules = extraNodeModules; this._hasteFS = hasteFS; - this._hasteMap = hasteMap; this._helpers = helpers; this._moduleCache = moduleCache; + this._moduleMap = moduleMap; this._platform = platform; this._platforms = platforms; this._preferNativePlatform = preferNativePlatform; this._resetResolutionCache(); } - _tryResolve(action: () => Promise, secondaryAction: () => ?Promise) { + _tryResolve(action: () => Promise, secondaryAction: () => ?Promise): Promise { return action().catch(error => { if (error.type !== 'UnableToResolveError') { throw error; @@ -219,7 +227,7 @@ class ResolutionRequest { }); } - _resolveHasteDependency(fromModule: Module, toModuleName: string) { + _resolveHasteDependency(fromModule: Module, toModuleName: string): Promise { toModuleName = normalizePath(toModuleName); let p = fromModule.getPackage(); @@ -230,23 +238,34 @@ class ResolutionRequest { } return p.then(realModuleName => { - let dep = this._hasteMap.getModule(realModuleName, this._platform); - if (dep && dep.type === 'Module') { - return dep; + const modulePath = this._moduleMap + .getModule(realModuleName, this._platform, /* supportsNativePlatform */ true); + if (modulePath != null) { + const module = this._moduleCache.getModule(modulePath); + /* temporary until we strengthen the typing */ + invariant(module.type === 'Module', 'expected Module type'); + return module; } let packageName = realModuleName; + let packagePath; while (packageName && packageName !== '.') { - dep = this._hasteMap.getModule(packageName, this._platform); - if (dep && dep.type === 'Package') { + packagePath = this._moduleMap + .getPackage(packageName, this._platform, /* supportsNativePlatform */ true); + if (packagePath != null) { break; } packageName = path.dirname(packageName); } - if (dep && dep.type === 'Package') { + if (packagePath != null) { + + const package_ = this._moduleCache.getPackage(packagePath); + /* temporary until we strengthen the typing */ + invariant(package_.type === 'Package', 'expected Package type'); + const potentialModulePath = path.join( - dep.root, + package_.root, path.relative(packageName, realModuleName) ); return this._tryResolve( @@ -379,7 +398,7 @@ class ResolutionRequest { } } - _loadAsFile(potentialModulePath: string, fromModule: Module, toModule: string) { + _loadAsFile(potentialModulePath: string, fromModule: Module, toModule: string): Promise { return Promise.resolve().then(() => { if (this._helpers.isAssetFile(potentialModulePath)) { let dirname = path.dirname(potentialModulePath); diff --git a/packages/metro-bundler/src/node-haste/ModuleCache.js b/packages/metro-bundler/src/node-haste/ModuleCache.js index cead5fc9..f19ce1ac 100644 --- a/packages/metro-bundler/src/node-haste/ModuleCache.js +++ b/packages/metro-bundler/src/node-haste/ModuleCache.js @@ -78,7 +78,7 @@ class ModuleCache { this._reporter = reporter; } - getModule(filePath: string) { + getModule(filePath: string): Module { if (!this._moduleCache[filePath]) { this._moduleCache[filePath] = new Module({ cache: this._cache, diff --git a/packages/metro-bundler/src/node-haste/index.js b/packages/metro-bundler/src/node-haste/index.js index a60c7daa..e1222c5c 100644 --- a/packages/metro-bundler/src/node-haste/index.js +++ b/packages/metro-bundler/src/node-haste/index.js @@ -42,6 +42,7 @@ import type {Options as TransformOptions} from '../JSTransformer/worker/worker'; import type GlobalTransformCache from '../lib/GlobalTransformCache'; import type {GetTransformCacheKey} from '../lib/TransformCache'; import type {Reporter} from '../lib/reporting'; +import type {ModuleMap} from './DependencyGraph/ResolutionRequest'; import type { Options as ModuleOptions, TransformCode, @@ -81,6 +82,7 @@ class DependencyGraph extends EventEmitter { _hasteMapError: ?Error; _helpers: DependencyGraphHelpers; _moduleCache: ModuleCache; + _moduleMap: ModuleMap; _loading: Promise; @@ -116,8 +118,9 @@ class DependencyGraph extends EventEmitter { const initializingPackagerLogEntry = log(createActionStartEntry('Initializing Packager')); this._opts.reporter.update({type: 'dep_graph_loading'}); - this._loading = this._haste.build().then(({hasteFS}) => { + this._loading = this._haste.build().then(({hasteFS, moduleMap}) => { this._hasteFS = hasteFS; + this._moduleMap = moduleMap; const hasteFSFiles = hasteFS.getAllFiles(); this._moduleCache = new ModuleCache({ @@ -153,9 +156,10 @@ class DependencyGraph extends EventEmitter { platforms: this._opts.platforms, }); - this._haste.on('change', ({eventsQueue, hasteFS: newHasteFS}) => { - this._hasteFS = newHasteFS; - eventsQueue.forEach(({type, filePath, stat}) => + this._haste.on('change', event => { + this._hasteFS = event.hasteFS; + this._moduleMap = event.moduleMap; + event.eventsQueue.forEach(({type, filePath, stat}) => this.processFileChange(type, filePath, stat) ); this.emit('change'); @@ -189,7 +193,7 @@ class DependencyGraph extends EventEmitter { * Returns a promise with the direct dependencies the module associated to * the given entryPath has. */ - getShallowDependencies(entryPath: string, transformOptions: mixed) { + getShallowDependencies(entryPath: string, transformOptions: TransformOptions) { return this._moduleCache .getModule(entryPath) .getDependencies(transformOptions); @@ -237,9 +241,9 @@ class DependencyGraph extends EventEmitter { entryPath: absPath, extraNodeModules: this._opts.extraNodeModules, hasteFS: this._hasteFS, - hasteMap: this._hasteMap, helpers: this._helpers, moduleCache: this._moduleCache, + moduleMap: this._moduleMap, platform, platforms: this._opts.platforms, preferNativePlatform: this._opts.preferNativePlatform,