Implementation of Metro's resolution logic for JavaScript modules, assets, and packages within React Native and Metro bundler projects.
npx @tessl/cli install tessl/npm-metro-resolver@0.83.00
# Metro Resolver
1
2
Metro Resolver is a JavaScript library that implements Metro's module resolution logic, providing the core functionality for resolving JavaScript modules, assets, and packages within React Native and Metro bundler projects. It handles complex resolution scenarios including package.json exports, imports, platform-specific files, asset resolution, and custom resolver implementations.
3
4
## Package Information
5
6
- **Package Name**: metro-resolver
7
- **Package Type**: npm
8
- **Language**: JavaScript/TypeScript
9
- **Installation**: `npm install metro-resolver`
10
11
## Core Imports
12
13
```javascript
14
const Resolver = require("metro-resolver");
15
const { resolve } = Resolver;
16
```
17
18
For ES modules:
19
20
```javascript
21
import Resolver from "metro-resolver";
22
const { resolve } = Resolver;
23
```
24
25
TypeScript imports (with type definitions):
26
27
```typescript
28
import {
29
resolve,
30
type ResolutionContext,
31
type Resolution,
32
type CustomResolver
33
} from "metro-resolver";
34
```
35
36
## Basic Usage
37
38
```javascript
39
const Resolver = require("metro-resolver");
40
41
// Create a resolution context (typically provided by Metro bundler)
42
const context = {
43
allowHaste: false,
44
assetExts: new Set(['png', 'jpg', 'jpeg', 'gif']),
45
sourceExts: ['js', 'json', 'ts', 'tsx'],
46
mainFields: ['browser', 'main'],
47
fileSystemLookup: (path) => ({ exists: true, type: 'f', realPath: path }),
48
doesFileExist: (path) => true,
49
getPackage: (packagePath) => require(packagePath),
50
getPackageForModule: (modulePath) => null,
51
nodeModulesPaths: ['/node_modules'],
52
originModulePath: '/app/src/index.js',
53
preferNativePlatform: false,
54
resolveAsset: (dirPath, name, ext) => [`${dirPath}/${name}${ext}`],
55
resolveHasteModule: () => undefined,
56
resolveHastePackage: () => undefined,
57
redirectModulePath: (path) => path,
58
customResolverOptions: {},
59
disableHierarchicalLookup: false,
60
extraNodeModules: null,
61
dev: false,
62
unstable_conditionNames: ['import', 'require'],
63
unstable_conditionsByPlatform: {},
64
unstable_enablePackageExports: true,
65
unstable_logWarning: console.warn
66
};
67
68
// Resolve a module
69
const resolution = Resolver.resolve(context, 'react-native', 'ios');
70
console.log(resolution);
71
// { type: 'sourceFile', filePath: '/node_modules/react-native/index.js' }
72
```
73
74
## Architecture
75
76
Metro Resolver is built around several key components:
77
78
- **Core Resolution Engine**: The main `resolve` function that orchestrates the resolution process
79
- **Resolution Context**: Configuration object containing all resolver settings and helper functions
80
- **Package Resolution**: Logic for resolving package entry points, exports, and imports fields
81
- **File System Integration**: Abstracted file system operations for flexibility across environments
82
- **Error Handling**: Comprehensive error types for different resolution failure scenarios
83
- **Asset Resolution**: Specialized handling for asset files with scaling variants
84
- **Platform Support**: Platform-specific file resolution for React Native development
85
86
## Capabilities
87
88
### Core Resolution
89
90
Main resolution function that handles all module resolution scenarios including relative paths, absolute paths, bare specifiers, and Haste modules.
91
92
```typescript { .api }
93
function resolve(
94
context: ResolutionContext,
95
moduleName: string,
96
platform: string | null
97
): Resolution;
98
99
type Resolution = FileResolution | Readonly<{ type: 'empty' }>;
100
101
type FileResolution = AssetResolution | SourceFileResolution;
102
103
interface SourceFileResolution {
104
readonly type: 'sourceFile';
105
readonly filePath: string;
106
}
107
108
interface AssetResolution {
109
readonly type: 'assetFiles';
110
readonly filePaths: ReadonlyArray<string>;
111
}
112
```
113
114
[Resolution Engine](./resolution-engine.md)
115
116
### Resolution Context
117
118
Configuration system that provides all the settings, file system operations, and helper functions needed for module resolution.
119
120
```typescript { .api }
121
interface ResolutionContext {
122
readonly allowHaste: boolean;
123
readonly assetExts: ReadonlySet<string>;
124
readonly sourceExts: ReadonlyArray<string>;
125
readonly customResolverOptions: CustomResolverOptions;
126
readonly disableHierarchicalLookup: boolean;
127
readonly doesFileExist: DoesFileExist;
128
readonly extraNodeModules?: Readonly<{ [string]: string }> | null;
129
readonly dev: boolean;
130
readonly fileSystemLookup: FileSystemLookup;
131
readonly getPackage: (packageJsonPath: string) => PackageJson | null;
132
readonly getPackageForModule: (absoluteModulePath: string) => PackageForModule | null;
133
readonly mainFields: ReadonlyArray<string>;
134
readonly originModulePath: string;
135
readonly nodeModulesPaths: ReadonlyArray<string>;
136
readonly preferNativePlatform: boolean;
137
readonly resolveAsset: ResolveAsset;
138
readonly redirectModulePath: (modulePath: string) => string | false;
139
readonly resolveHasteModule: (name: string) => string | undefined;
140
readonly resolveHastePackage: (name: string) => string | undefined;
141
readonly resolveRequest?: CustomResolver;
142
readonly dependency?: any;
143
readonly isESMImport?: boolean;
144
readonly unstable_conditionNames: ReadonlyArray<string>;
145
readonly unstable_conditionsByPlatform: Readonly<{ [platform: string]: ReadonlyArray<string> }>;
146
readonly unstable_enablePackageExports: boolean;
147
readonly unstable_logWarning: (message: string) => void;
148
}
149
```
150
151
[Resolution Context](./resolution-context.md)
152
153
### Error Handling
154
155
Comprehensive error types for different resolution failure scenarios with detailed diagnostic information.
156
157
```typescript { .api }
158
class FailedToResolveNameError extends Error {
159
dirPaths: ReadonlyArray<string>;
160
extraPaths: ReadonlyArray<string>;
161
}
162
163
class FailedToResolvePathError extends Error {
164
candidates: FileAndDirCandidates;
165
}
166
167
class InvalidPackageError extends Error {
168
fileCandidates: FileCandidates;
169
indexCandidates: FileCandidates;
170
mainModulePath: string;
171
packageJsonPath: string;
172
}
173
174
class FailedToResolveUnsupportedError extends Error {
175
constructor(message: string);
176
}
177
```
178
179
[Error Handling](./error-handling.md)
180
181
### Package Resolution
182
183
Advanced package resolution supporting modern Node.js features like package.json exports/imports fields and conditional exports.
184
185
```typescript { .api }
186
interface PackageJson {
187
readonly name?: string;
188
readonly main?: string;
189
readonly exports?: ExportsField;
190
readonly imports?: ExportsLikeMap;
191
}
192
193
194
interface PackageInfo {
195
readonly packageJson: PackageJson;
196
readonly rootPath: string;
197
}
198
```
199
200
[Package Resolution](./package-resolution.md)
201
202
### Asset Resolution
203
204
Specialized handling for asset files including support for scaling variants and platform-specific assets.
205
206
```typescript { .api }
207
type ResolveAsset = (
208
dirPath: string,
209
assetName: string,
210
extension: string
211
) => ReadonlyArray<string> | undefined;
212
213
function resolveAsset(
214
context: ResolutionContext,
215
filePath: string
216
): AssetResolution | null;
217
```
218
219
[Asset Resolution](./asset-resolution.md)
220
221
### Custom Resolvers
222
223
Extensibility system allowing custom resolution logic to be integrated into the resolution pipeline.
224
225
```typescript { .api }
226
type CustomResolver = (
227
context: CustomResolutionContext,
228
moduleName: string,
229
platform: string | null
230
) => Resolution;
231
232
interface CustomResolutionContext extends ResolutionContext {
233
readonly resolveRequest: CustomResolver;
234
}
235
236
type CustomResolverOptions = Readonly<{
237
[option: string]: unknown;
238
}>;
239
```
240
241
[Custom Resolvers](./custom-resolvers.md)
242
243
### Utility Functions
244
245
Utility functions for working with resolution candidates and formatting.
246
247
```typescript { .api }
248
function formatFileCandidates(candidates: FileCandidates): string;
249
```
250
251
## Types
252
253
```typescript { .api }
254
type Result<TResolution, TCandidates> =
255
| { readonly type: 'resolved'; readonly resolution: TResolution }
256
| { readonly type: 'failed'; readonly candidates: TCandidates };
257
258
type AssetFileResolution = ReadonlyArray<string>;
259
260
type FileCandidates =
261
| { readonly type: 'asset'; readonly name: string }
262
| {
263
readonly type: 'sourceFile';
264
filePathPrefix: string;
265
readonly candidateExts: ReadonlyArray<string>;
266
};
267
268
interface FileAndDirCandidates {
269
readonly dir: FileCandidates | null;
270
readonly file: FileCandidates | null;
271
}
272
273
type DoesFileExist = (filePath: string) => boolean;
274
275
type FileSystemLookup = (
276
absoluteOrProjectRelativePath: string
277
) => { exists: false } | { exists: true; type: 'f' | 'd'; realPath: string };
278
279
interface PackageForModule extends PackageInfo {
280
readonly packageRelativePath: string;
281
}
282
283
type ExportsLikeMap = Readonly<{
284
[subpathOrCondition: string]: string | ExportsLikeMap | null;
285
}>;
286
287
type ExportMapWithFallbacks = Readonly<{
288
[subpath: string]: string | ExportsLikeMap | null | ExportValueWithFallback;
289
}>;
290
291
type ExportValueWithFallback =
292
| ReadonlyArray<ExportsLikeMap | string>
293
| ReadonlyArray<ReadonlyArray<unknown>>;
294
295
type ExportsField =
296
| string
297
| ReadonlyArray<string>
298
| ExportValueWithFallback
299
| ExportsLikeMap
300
| ExportMapWithFallbacks;
301
302
type FlattenedExportMap = ReadonlyMap<string, string | null>;
303
304
type NormalizedExportsLikeMap = Map<string, null | string | ExportsLikeMap>;
305
```