Skip to content

Commit af40ab0

Browse files
authored
Add asset resolutions and align details in Metro exports RFC (#603)
1 parent 1e86be4 commit af40ab0

File tree

1 file changed

+26
-10
lines changed

1 file changed

+26
-10
lines changed

proposals/0534-metro-package-exports-support.md

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ The following features and considerations are detailed in this section:
8989
- [Conditional exports: `"import"` and `"require"`](#conditional-exports-import-and-require)
9090
- [Conditional exports: Community definitions and `"browser"`](#conditional-exports-community-definitions-and-browser)
9191
- [Conditional exports: User conditions and configuration](#conditional-exports-user-conditions-and-configuration)
92+
- [Asset resolutions](#asset-resolutions)
9293
- [Opting into strict `"exports"` handling](#opting-into-strict-exports-handling)
9394

9495
The following features will be implemented without any anticipated behaviour differences or special notes (links go to Node.js spec):
@@ -223,7 +224,7 @@ import BazComponent from './BazComponent.mjs';
223224

224225
- **Breaking**: Under `"exports"`, Metro will not resolve platform-specific extensions for listed package entry points.
225226
- When resolving any import specifier:
226-
- If the package defines `"exports"` and the import specifier (after expanding `sourceExts`) is matched, the package-defined path mapping will be used with no further transformation.
227+
- If the package defines `"exports"` and the exact import specifier is matched, the package-defined path mapping will be used with no further transformation.
227228
- If there is no match in `"exports"`, Metro will look for files which match the import specifier, trying all extension variants (existing resolution logic).
228229
- With this decision, we will have narrowed support for platform-specific extensions in packages. We will communicate to React Native package authors that alternative patterns should be used.
229230
- We have no near-term plans to drop platform-specific extensions for packages not using `"exports"`, or in app code.
@@ -233,8 +234,10 @@ Note: We may yet (unplanned) independently make the platform-specific extensions
233234

234235
#### Illustrated
235236

236-
```json
237+
```js
237238
"exports": {
239+
// Node.js recommends that packages list extensionless specifiers
240+
// for compatibility
238241
"./FooComponent": "./src/FooComponent.js",
239242
"./FooComponent.js": "./src/FooComponent.js",
240243
}
@@ -244,6 +247,7 @@ Import specifiers listed in `"exports"` will be used when matched. Alternative p
244247

245248
```js
246249
import FooComponent from 'pkg/FooComponent';
250+
// (Metro will not expand this specifier using sourceExts)
247251
// Reads from "exports":
248252
// pkg/src/FooComponent.js
249253
@@ -389,14 +393,10 @@ module.exports = {
389393
// (default: ['react-native'])
390394
conditionNames: ['react-native', 'production'],
391395
392-
// A function that will be used to assert additional
393-
// condition names when resolving an exports field path
394-
getAssertedConditions: ({ platform }) => {
395-
if (platform === 'web') {
396-
return ['browser'];
397-
}
398-
399-
return [];
396+
// The set of additional condition names to dynamically
397+
// assert by platform
398+
conditionsByPlatform: {
399+
web: ['browser'],
400400
},
401401
},
402402
};
@@ -406,6 +406,22 @@ The exact name and shape of these options may change during implementation. Nami
406406

407407
In addition, `resolver.resolveRequest` will continue to provide an escape hatch from Metro's handling of conditional exports, should an app need to override imports from a given package.
408408
409+
### Asset resolutions
410+
411+
In addition to source files, Metro supports the concept of *asset files*. In addition to being bundled separately, asset files may have different resolution suffixes (configured via `resolver.assetResolutions`), for example `./img/check.png` may resolve a set of files that includes `./img/check@2x.png`, selected depending on target device.
412+
413+
Since this concept is not expressible using the existing `"exports"` spec (see [Subpath patterns](#subpath-patterns)), it makes sense to add Metro-specific functionality to continue supporting this feature.
414+
415+
We support existing config options that can be provided to customise how asset resolution behaves. These should remain load-bearing whether a file is resolved via `"exports"` or by filesystem resolution:
416+
417+
- [`resolver.isAssetFile`](https://facebook.github.io/metro/docs/resolution/#isassetfile-string--boolean)
418+
- [`resolver.resolveAsset`](https://facebook.github.io/metro/docs/resolution/#resolveasset-dirpath-string-assetname-string-extension-string--readonlyarraystring)
419+
420+
**Proposed**:
421+
422+
- Handle asset resolutions by calling `isAssetFile` on the subpath mapped to by `"exports"`. If this returns `true`, then expand asset resolutions by calling `resolveAsset` against this path.
423+
- As with source files, if a subpath is not matched in `"exports"` and falls back to legacy resolution, a package encapsulation warning will be logged (using the base file name).
424+
409425
### Additional consideration: Jest
410426
411427
Because Metro's implementation of `"exports"` will not be strict, package resolution behaviour will be misaligned between Metro and Jest (where support was [added in Jest 28](https://jestjs.io/blog/2022/04/25/jest-28#packagejson-exports)). In projects consuming several exports-enabled dependencies, it is likely that misalignments will lead to confusing test failures.

0 commit comments

Comments
 (0)