-
Notifications
You must be signed in to change notification settings - Fork 634
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reserve import specifiers beginning '#' for future package imports su…
…pport Summary: We don't have [package.json subpath imports](https://nodejs.org/api/packages.html#subpath-imports) support yet, but we'd like to give ourselves room to implement it as a non-breaking change at some point in Metro 0.81 / React Native 0.76. This reserves a space at the right place in the resolution algorithm to add an implementation later, according to https://nodejs.org/api/esm.html#resolution-algorithm-specification. The breaking change here is that `#foo` is no longer a valid package or Haste name, or browser-field key. It will always be interpreted at a subpath import. This is consistent with the rest of the ecosystem and so shouldn't cause any real-world friction. Changelog: ``` - **[Breaking]** Resolver: Reserve import specifiers beginning '#' exclusively for future subpath imports support. ``` Reviewed By: huntie Differential Revision: D64316184 fbshipit-source-id: d48613e66e904812aef7fef0e2e6fe0e54b5f4ff
- Loading branch information
1 parent
5e96d17
commit c1c80c7
Showing
6 changed files
with
111 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
packages/metro-resolver/src/__tests__/package-imports-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @flow strict-local | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
|
||
import {createResolutionContext} from './utils'; | ||
|
||
// Implementation of PACKAGE_IMPORTS_RESOLVE described in https://nodejs.org/api/esm.html | ||
describe('subpath imports resolution support', () => { | ||
let Resolver; | ||
const mockRedirectModulePath = jest.fn(); | ||
|
||
beforeEach(() => { | ||
jest.resetModules(); | ||
jest.mock('../PackageResolve', () => ({ | ||
...jest.requireActual('../PackageResolve'), | ||
redirectModulePath: mockRedirectModulePath, | ||
})); | ||
Resolver = require('../index'); | ||
}); | ||
|
||
test('specifiers beginning # are reserved for future package imports support', () => { | ||
const mockNeverCalledFn = jest.fn(); | ||
const mockCustomResolver = jest | ||
.fn() | ||
.mockImplementation((ctx, ...args) => ctx.resolveRequest(ctx, ...args)); | ||
|
||
const context = { | ||
...createResolutionContext({}), | ||
originModulePath: '/root/src/main.js', | ||
doesFileExist: mockNeverCalledFn, | ||
fileSystemLookup: mockNeverCalledFn, | ||
redirectModulePath: mockNeverCalledFn, | ||
resolveHasteModule: mockNeverCalledFn, | ||
resolveHastePackage: mockNeverCalledFn, | ||
resolveRequest: mockCustomResolver, | ||
}; | ||
|
||
expect(() => Resolver.resolve(context, '#foo', null)).toThrow( | ||
new Resolver.FailedToResolveUnsupportedError( | ||
'Specifier starts with "#" but subpath imports are not currently supported.', | ||
), | ||
); | ||
|
||
// Ensure any custom resolver *is* still called first. | ||
expect(mockCustomResolver).toBeCalledTimes(1); | ||
expect(mockCustomResolver).toBeCalledWith( | ||
expect.objectContaining({ | ||
originModulePath: '/root/src/main.js', | ||
}), | ||
'#foo', | ||
null, | ||
); | ||
|
||
// Ensure package imports precedes any other attempt at resolution for a '#' specifier. | ||
expect(mockNeverCalledFn).not.toHaveBeenCalled(); | ||
expect(mockRedirectModulePath).not.toHaveBeenCalled(); | ||
}); | ||
}); |
20 changes: 20 additions & 0 deletions
20
packages/metro-resolver/src/errors/FailedToResolveUnsupportedError.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @flow strict | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
|
||
'use strict'; | ||
|
||
class FailedToResolveUnsupportedError extends Error { | ||
constructor(message: string) { | ||
super(message); | ||
} | ||
} | ||
|
||
module.exports = FailedToResolveUnsupportedError; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters