Skip to content

Commit 7e92227

Browse files
huntiefacebook-github-bot
authored andcommitted
Fix resolution edge case for package subpaths redirected by mainFields
Summary: Simplifies logic in `metro-resolver` by colocating "browser" spec resolution in `resolveModulePath`, which addresses an edge case (see test changes). Changelog: **[Fix]** Extensionless `mainFields` mappings in a `package.json` will be respected when resolving subpath package specifiers Reviewed By: robhogan Differential Revision: D43699921 fbshipit-source-id: 2e550eac3359767826715fc7d65fcb3f34013068
1 parent 4c520ed commit 7e92227

File tree

3 files changed

+28
-32
lines changed

3 files changed

+28
-32
lines changed

packages/metro-resolver/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
"prepare-release": "test -d build && rm -rf src.real && mv src src.real && mv build src",
1212
"cleanup-release": "test ! -e build && mv src build && mv src.real src"
1313
},
14-
"dependencies": {
15-
"invariant": "^2.2.4"
16-
},
1714
"license": "MIT",
1815
"engines": {
1916
"node": ">=16"

packages/metro-resolver/src/resolve.js

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import formatFileCandidates from './errors/formatFileCandidates';
3030
import {getPackageEntryPoint} from './PackageResolve';
3131
import {resolvePackageTargetFromExports} from './PackageExportsResolve';
3232
import resolveAsset from './resolveAsset';
33-
import invariant from 'invariant';
3433

3534
function resolve(
3635
context: ResolutionContext,
@@ -51,7 +50,11 @@ function resolve(
5150
}
5251

5352
if (isRelativeImport(moduleName) || path.isAbsolute(moduleName)) {
54-
return resolveModulePath(context, moduleName, platform);
53+
const result = resolvePackage(context, moduleName, platform);
54+
if (result.type === 'failed') {
55+
throw new FailedToResolvePathError(result.candidates);
56+
}
57+
return result.resolution;
5558
}
5659

5760
const realModuleName = context.redirectModulePath(moduleName);
@@ -75,7 +78,11 @@ function resolve(
7578
originModulePath.indexOf(path.sep, fromModuleParentIdx),
7679
);
7780
const absPath = path.join(originModuleDir, realModuleName);
78-
return resolveModulePath(context, absPath, platform);
81+
const result = resolvePackage(context, absPath, platform);
82+
if (result.type === 'failed') {
83+
throw new FailedToResolvePathError(result.candidates);
84+
}
85+
return result.resolution;
7986
}
8087

8188
if (context.allowHaste && !isDirectImport) {
@@ -151,19 +158,26 @@ function resolveModulePath(
151158
context: ResolutionContext,
152159
toModuleName: string,
153160
platform: string | null,
154-
): Resolution {
161+
): Result<Resolution, FileAndDirCandidates> {
155162
const modulePath = path.isAbsolute(toModuleName)
156163
? resolveWindowsPath(toModuleName)
157164
: path.join(path.dirname(context.originModulePath), toModuleName);
158165
const redirectedPath = context.redirectModulePath(modulePath);
159166
if (redirectedPath === false) {
160-
return {type: 'empty'};
167+
return resolvedAs({type: 'empty'});
161168
}
162-
const result = resolvePackage(context, redirectedPath, platform);
163-
if (result.type === 'resolved') {
164-
return result.resolution;
169+
170+
const dirPath = path.dirname(redirectedPath);
171+
const fileName = path.basename(redirectedPath);
172+
const fileResult = resolveFile(context, dirPath, fileName, platform);
173+
if (fileResult.type === 'resolved') {
174+
return fileResult;
165175
}
166-
throw new FailedToResolvePathError(result.candidates);
176+
const dirResult = resolvePackageEntryPoint(context, redirectedPath, platform);
177+
if (dirResult.type === 'resolved') {
178+
return dirResult;
179+
}
180+
return failedFor({file: fileResult.candidates, dir: dirResult.candidates});
167181
}
168182

169183
/**
@@ -192,7 +206,7 @@ function resolveHasteName(
192206
const packageDirPath = path.dirname(packageJsonPath);
193207
const pathInModule = moduleName.substring(packageName.length + 1);
194208
const potentialModulePath = path.join(packageDirPath, pathInModule);
195-
const result = resolvePackage(context, potentialModulePath, platform);
209+
const result = resolveModulePath(context, potentialModulePath, platform);
196210
if (result.type === 'resolved') {
197211
return result;
198212
}
@@ -240,11 +254,6 @@ function resolvePackage(
240254
modulePath: string,
241255
platform: string | null,
242256
): Result<Resolution, FileAndDirCandidates> {
243-
invariant(
244-
path.isAbsolute(modulePath),
245-
'resolvePackage expects an absolute module path',
246-
);
247-
248257
if (context.unstable_enablePackageExports) {
249258
const pkg = context.getPackageForModule(modulePath);
250259
const exportsField = pkg?.packageJson.exports;
@@ -283,17 +292,7 @@ function resolvePackage(
283292
}
284293
}
285294

286-
const dirPath = path.dirname(modulePath);
287-
const fileName = path.basename(modulePath);
288-
const fileResult = resolveFile(context, dirPath, fileName, platform);
289-
if (fileResult.type === 'resolved') {
290-
return fileResult;
291-
}
292-
const dirResult = resolvePackageEntryPoint(context, modulePath, platform);
293-
if (dirResult.type === 'resolved') {
294-
return dirResult;
295-
}
296-
return failedFor({file: fileResult.candidates, dir: dirResult.candidates});
295+
return resolveModulePath(context, modulePath, platform);
297296
}
298297

299298
/**

packages/metro/src/DeltaBundler/__tests__/resolver-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,7 +1134,8 @@ type MockFSDirContents = $ReadOnly<{
11341134
type: 'sourceFile',
11351135
filePath: p('/root/emptyModule.js'),
11361136
});
1137-
// Existing limitation: Subpaths of a package are not redirected by "browser"
1137+
// Existing limitation: Subpaths of a package are not redirected by
1138+
// a base package name redirection in "browser"
11381139
expect(
11391140
resolver.resolve(
11401141
p('/root/node_modules/aPackage/index.js'),
@@ -1855,12 +1856,11 @@ type MockFSDirContents = $ReadOnly<{
18551856
type: 'sourceFile',
18561857
filePath: p('/root/aPackage/client.js'),
18571858
});
1858-
// TODO: Is this behaviour correct?
18591859
expect(
18601860
resolver.resolve(p('/root/index.js'), 'aPackage/main'),
18611861
).toEqual({
18621862
type: 'sourceFile',
1863-
filePath: p('/root/aPackage/main.js'),
1863+
filePath: p('/root/aPackage/client.js'),
18641864
});
18651865
});
18661866
});

0 commit comments

Comments
 (0)