Implementation of Metro's resolution logic for JavaScript modules, assets, and packages within React Native and Metro bundler projects.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The core resolution engine handles all module resolution scenarios including relative paths, absolute paths, bare specifiers, and Haste modules. It orchestrates the entire resolution process through a series of specialized resolvers.
The primary entry point for all module resolution operations.
/**
* Resolve a module name to a file path or asset collection based on the resolution context
* @param context - Resolution context containing configuration and helper functions
* @param moduleName - Module name to resolve (relative, absolute, or bare specifier)
* @param platform - Target platform (e.g., 'ios', 'android', 'web') for platform-specific resolution
* @returns Resolution result containing file path or asset collection
*/
function resolve(
context: ResolutionContext,
moduleName: string,
platform: string | null
): Resolution;Usage Examples:
const Resolver = require("metro-resolver");
// Resolve relative import
const relativeResult = Resolver.resolve(context, './utils/helper', 'ios');
// { type: 'sourceFile', filePath: '/app/src/utils/helper.ios.js' }
// Resolve bare specifier
const packageResult = Resolver.resolve(context, 'lodash', null);
// { type: 'sourceFile', filePath: '/node_modules/lodash/index.js' }
// Resolve asset
const assetResult = Resolver.resolve(context, './icon.png', 'ios');
// { type: 'assetFiles', filePaths: ['./icon@2x.ios.png', './icon.ios.png'] }
// Handle empty resolution (excluded module)
const emptyResult = Resolver.resolve(context, 'excluded-module', null);
// { type: 'empty' }Different types of resolution outcomes based on the target module.
type Resolution = FileResolution | Readonly<{ type: 'empty' }>;
type FileResolution = AssetResolution | SourceFileResolution;
interface SourceFileResolution {
readonly type: 'sourceFile';
readonly filePath: string;
}
interface AssetResolution {
readonly type: 'assetFiles';
readonly filePaths: ReadonlyArray<string>;
}The resolver follows a systematic process:
# prefixed importsThe resolver supports platform-specific file resolution for React Native development.
Resolution Priority:
Component.ios.js)Component.native.js) if preferNativePlatform is trueComponent.js)Usage Example:
// With platform = 'ios', the resolver will try:
// 1. ./Component.ios.js
// 2. ./Component.native.js (if preferNativePlatform: true)
// 3. ./Component.js
const result = Resolver.resolve(context, './Component', 'ios');The resolver attempts multiple extensions based on configuration.
Resolution Order:
.js, .ts, .tsx, etc.).png, .jpg, etc.)For bare specifiers, the resolver searches through the node_modules hierarchy.
Search Order:
Example Hierarchy:
/project/src/components/Button.js
-> /project/src/components/node_modules/package
-> /project/src/node_modules/package
-> /project/node_modules/package
-> /node_modules/packageThe resolver can return empty resolutions for excluded modules.
interface EmptyResolution {
readonly type: 'empty';
}This is useful for:
Usage Example:
// If redirectModulePath returns false for a module
const context = {
// ... other config
redirectModulePath: (path) => {
if (path.includes('server-only')) return false;
return path;
}
};
const result = Resolver.resolve(context, 'server-only-module', null);
// { type: 'empty' }