From 203bb0ddfd1f600d36501d19bcc6585cfc4fd291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Thu, 5 Apr 2018 08:54:52 -0700 Subject: [PATCH] Adds an experimental hook for custom resolutions Reviewed By: mjesun Differential Revision: D7337022 fbshipit-source-id: fea1ee345e4d3b5713fed6cdc33869fbba6f21e2 --- packages/metro-resolver/src/index.js | 1 + packages/metro-resolver/src/resolve.js | 29 +++++++++++++++---- packages/metro-resolver/src/types.js | 2 ++ packages/metro/src/Bundler/index.js | 3 ++ packages/metro/src/Config.js | 8 +++++ .../src/ModuleGraph/node-haste/node-haste.js | 3 ++ packages/metro/src/Server/index.js | 4 +++ packages/metro/src/index.js | 1 + packages/metro/src/legacy.js | 1 + .../metro/src/node-haste/DependencyGraph.js | 3 ++ .../DependencyGraph/ModuleResolution.js | 2 ++ packages/metro/src/shared/types.flow.js | 2 ++ 12 files changed, 54 insertions(+), 5 deletions(-) diff --git a/packages/metro-resolver/src/index.js b/packages/metro-resolver/src/index.js index af348463..ff552213 100644 --- a/packages/metro-resolver/src/index.js +++ b/packages/metro-resolver/src/index.js @@ -18,6 +18,7 @@ export type { } from './resolve'; export type { AssetFileResolution, + CustomResolver, FileAndDirCandidates, FileCandidates, FileResolution, diff --git a/packages/metro-resolver/src/resolve.js b/packages/metro-resolver/src/resolve.js index b7fe03a5..33faf065 100644 --- a/packages/metro-resolver/src/resolve.js +++ b/packages/metro-resolver/src/resolve.js @@ -20,6 +20,7 @@ const path = require('path'); import type { AssetFileResolution, + CustomResolver, FileAndDirCandidates, FileCandidates, FileResolution, @@ -29,9 +30,10 @@ import type { export type ResolutionContext = ModulePathContext & HasteContext & { - originModulePath: string, allowHaste: boolean, extraNodeModules: ?{[string]: string}, + originModulePath: string, + resolveRequest?: ?CustomResolver, }; function resolve( @@ -39,9 +41,13 @@ function resolve( moduleName: string, platform: string | null, ): Resolution { - if (isRelativeImport(moduleName) || isAbsolutePath(moduleName)) { + if ( + !context.resolveRequest && + (isRelativeImport(moduleName) || isAbsolutePath(moduleName)) + ) { return resolveModulePath(context, moduleName, platform); } + const realModuleName = context.redirectModulePath(moduleName); // exclude if (realModuleName === false) { @@ -49,7 +55,10 @@ function resolve( } const {originModulePath} = context; - if (isRelativeImport(realModuleName) || isAbsolutePath(realModuleName)) { + if ( + !context.resolveRequest && + (isRelativeImport(realModuleName) || isAbsolutePath(realModuleName)) + ) { // derive absolute path /.../node_modules/originModuleDir/realModuleName const fromModuleParentIdx = originModulePath.lastIndexOf('node_modules' + path.sep) + 13; @@ -61,8 +70,18 @@ function resolve( return resolveModulePath(context, absPath, platform); } - // At that point we only have module names that - // aren't relative paths nor absolute paths. + if (context.resolveRequest) { + try { + const resolution = context.resolveRequest( + moduleName, + context.originModulePath, + ); + if (resolution) { + return {type: 'sourceFile', filePath: resolution}; + } + } catch (error) {} + } + if (context.allowHaste) { const normalizedName = normalizePath(realModuleName); const result = resolveHasteName(context, normalizedName, platform); diff --git a/packages/metro-resolver/src/types.js b/packages/metro-resolver/src/types.js index a1a8ce50..891ec982 100644 --- a/packages/metro-resolver/src/types.js +++ b/packages/metro-resolver/src/types.js @@ -42,3 +42,5 @@ export type FileCandidates = +filePathPrefix: string, +candidateExts: $ReadOnlyArray, |}; + +export type CustomResolver = (string, string) => string; diff --git a/packages/metro/src/Bundler/index.js b/packages/metro/src/Bundler/index.js index cdf8caad..34cca7e6 100644 --- a/packages/metro/src/Bundler/index.js +++ b/packages/metro/src/Bundler/index.js @@ -36,6 +36,7 @@ import type {Reporter} from '../lib/reporting'; import type Module from '../node-haste/Module'; import type {BabelSourceMap} from '@babel/core'; import type {CacheStore} from 'metro-cache'; +import type {CustomResolver} from 'metro-resolver'; import type { MetroSourceMapSegmentTuple, MetroSourceMap, @@ -98,6 +99,7 @@ export type Options = {| +providesModuleNodeModules?: Array, +reporter: Reporter, +resetCache: boolean, + +resolveRequest: ?CustomResolver, +sourceExts: Array, +transformCache: TransformCache, +transformModulePath: string, @@ -163,6 +165,7 @@ class Bundler { providesModuleNodeModules: opts.providesModuleNodeModules || defaults.providesModuleNodeModules, reporter: opts.reporter, + resolveRequest: opts.resolveRequest, resetCache: opts.resetCache, sourceExts: opts.sourceExts, transformCode: this._cachedTransformCode.bind(this), diff --git a/packages/metro/src/Config.js b/packages/metro/src/Config.js index 54e72c4c..b22988fa 100644 --- a/packages/metro/src/Config.js +++ b/packages/metro/src/Config.js @@ -23,6 +23,7 @@ import type {TransformedCode} from './JSTransformer/worker'; import type {DynamicRequiresBehavior} from './ModuleGraph/worker/collectDependencies'; import type {IncomingMessage, ServerResponse} from 'http'; import type {CacheStore} from 'metro-cache'; +import type {CustomResolver} from 'metro-resolver'; type Middleware = (IncomingMessage, ServerResponse, ?() => mixed) => mixed; @@ -141,6 +142,12 @@ export type ConfigT = { */ postProcessBundleSourcemap: PostProcessBundleSourcemap, + /** + * An optional function used to resolve requests. Ignored when the request can + * be resolved through Haste. + */ + resolveRequest: ?CustomResolver, + /** * Path to a require-able module that exports: * - a `getHasteName(filePath)` method that returns `hasteName` for module at @@ -186,6 +193,7 @@ const DEFAULT = ({ getUseGlobalHotkey: () => true, postMinifyProcess: x => x, postProcessBundleSourcemap: ({code, map, outFileName}) => ({code, map}), + resolveRequest: null, getModulesRunBeforeMainModule: () => [], getWorkerPath: () => null, }: ConfigT); diff --git a/packages/metro/src/ModuleGraph/node-haste/node-haste.js b/packages/metro/src/ModuleGraph/node-haste/node-haste.js index 6bf45e0a..588d5200 100644 --- a/packages/metro/src/ModuleGraph/node-haste/node-haste.js +++ b/packages/metro/src/ModuleGraph/node-haste/node-haste.js @@ -29,10 +29,12 @@ const {ModuleMap} = require('jest-haste-map'); import type {Moduleish} from '../../node-haste/DependencyGraph/ResolutionRequest'; import type {ResolveFn, TransformedCodeFile} from '../types.flow'; import type {Extensions, Path} from './node-haste.flow'; +import type {CustomResolver} from 'metro-resolver'; type ResolveOptions = {| assetExts: Extensions, extraNodeModules: {[id: string]: string}, + resolveRequest?: ?CustomResolver, +sourceExts: Extensions, transformedFiles: {[path: Path]: TransformedCodeFile}, |}; @@ -147,6 +149,7 @@ exports.createResolveFn = function(options: ResolveOptions): ResolveFn { preferNativePlatform: true, resolveAsset: (dirPath, assetName, platform) => assetResolutionCache.resolve(dirPath, assetName, platform), + resolveRequest: options.resolveRequest, sourceExts, }); diff --git a/packages/metro/src/Server/index.js b/packages/metro/src/Server/index.js index 7bf67944..a4330c3f 100644 --- a/packages/metro/src/Server/index.js +++ b/packages/metro/src/Server/index.js @@ -54,6 +54,7 @@ import type { } from '../Bundler'; import type {CacheStore} from 'metro-cache'; import type {Delta, Graph} from '../DeltaBundler'; +import type {CustomResolver} from 'metro-resolver'; import type {MetroSourceMap} from 'metro-source-map'; import type {TransformCache} from '../lib/TransformCaching'; import type {Symbolicate} from './symbolicate/symbolicate'; @@ -102,6 +103,7 @@ class Server { maxWorkers: number, minifierPath: string, platforms: Array, + resolveRequest: ?CustomResolver, polyfillModuleNames: Array, postMinifyProcess: PostMinifyProcess, postProcessBundleSourcemap: PostProcessBundleSourcemap, @@ -109,6 +111,7 @@ class Server { providesModuleNodeModules?: Array, reporter: Reporter, resetCache: boolean, + resolveRequest: ?CustomResolver, +getModulesRunBeforeMainModule: (entryFilePath: string) => Array, +getRunModuleStatement: (number | string) => string, silent: boolean, @@ -177,6 +180,7 @@ class Server { providesModuleNodeModules: options.providesModuleNodeModules, reporter, resetCache: options.resetCache || false, + resolveRequest: options.resolveRequest, silent: options.silent || false, sourceExts: options.assetTransforms ? sourceExts.concat(assetExts) diff --git a/packages/metro/src/index.js b/packages/metro/src/index.js index e3b5c2e7..ae4fa8ea 100644 --- a/packages/metro/src/index.js +++ b/packages/metro/src/index.js @@ -141,6 +141,7 @@ async function runMetro({ providesModuleNodeModules, resetCache, reporter, + resolveRequest: normalizedConfig.resolveRequest, sourceExts: normalizedConfig.assetTransforms ? sourceExts.concat(assetExts) : sourceExts, diff --git a/packages/metro/src/legacy.js b/packages/metro/src/legacy.js index 1b74cee0..c89cb3b7 100644 --- a/packages/metro/src/legacy.js +++ b/packages/metro/src/legacy.js @@ -196,6 +196,7 @@ function toServerOptions(options: Options): ServerOptions { providesModuleNodeModules: options.providesModuleNodeModules, reporter: options.reporter, resetCache: options.resetCache, + resolveRequest: options.resolveRequest, silent: options.silent, sourceExts: options.sourceExts, transformCache: options.transformCache || TransformCaching.useTempDir(), diff --git a/packages/metro/src/node-haste/DependencyGraph.js b/packages/metro/src/node-haste/DependencyGraph.js index 999fe733..e2d7d3a3 100644 --- a/packages/metro/src/node-haste/DependencyGraph.js +++ b/packages/metro/src/node-haste/DependencyGraph.js @@ -40,6 +40,7 @@ import type {ModuleMap} from './DependencyGraph/ModuleResolution'; import type {TransformCode} from './Module'; import type Package from './Package'; import type {HasteFS} from './types'; +import type {CustomResolver} from 'metro-resolver'; type Options = {| +assetExts: Array, @@ -58,6 +59,7 @@ type Options = {| +providesModuleNodeModules: Array, +reporter: Reporter, +resetCache: boolean, + +resolveRequest: ?CustomResolver, +sourceExts: Array, +transformCache: TransformCache, +transformCode: TransformCode, @@ -192,6 +194,7 @@ class DependencyGraph extends EventEmitter { preferNativePlatform: true, resolveAsset: (dirPath, assetName, platform) => this._assetResolutionCache.resolve(dirPath, assetName, platform), + resolveRequest: this._opts.resolveRequest, sourceExts: this._opts.sourceExts, }); } diff --git a/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js b/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js index 017da557..94df84e6 100644 --- a/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js +++ b/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js @@ -17,6 +17,7 @@ const path = require('path'); const util = require('util'); import type { + CustomResolver, DoesFileExist, IsAssetFile, ResolveAsset, @@ -70,6 +71,7 @@ type Options = {| +preferNativePlatform: boolean, +moduleMap: ModuleMap, +resolveAsset: ResolveAsset, + +resolveRequest: ?CustomResolver, +sourceExts: Array, |}; diff --git a/packages/metro/src/shared/types.flow.js b/packages/metro/src/shared/types.flow.js index 59f05a8e..09d91112 100644 --- a/packages/metro/src/shared/types.flow.js +++ b/packages/metro/src/shared/types.flow.js @@ -23,6 +23,7 @@ import type {GlobalTransformCache} from '../lib/GlobalTransformCache'; import type {TransformCache} from '../lib/TransformCaching'; import type {Reporter} from '../lib/reporting'; import type {CacheStore} from 'metro-cache'; +import type {CustomResolver} from 'metro-resolver'; import type { MetroSourceMap, MetroSourceMapSegmentTuple, @@ -102,6 +103,7 @@ export type Options = {| providesModuleNodeModules?: Array, reporter?: Reporter, resetCache?: boolean, + resolveRequest: ?CustomResolver, +getModulesRunBeforeMainModule: (entryPoint: string) => Array, silent?: boolean, +sourceExts: ?Array,