Skip to content

Move AssetRegistry implementation into main package, expose as public API (#57369)#57369

Open
huntie wants to merge 2 commits into
react:mainfrom
huntie:export-D109019622
Open

Move AssetRegistry implementation into main package, expose as public API (#57369)#57369
huntie wants to merge 2 commits into
react:mainfrom
huntie:export-D109019622

Conversation

@huntie

@huntie huntie commented Jun 29, 2026

Copy link
Copy Markdown
Member

Summary:

Problem

The separate react-native/assets-registry package includes a longstanding ecosystem footgun.

registry.js holds asset state in a module-scoped variable, which makes the package a stateful singleton: exactly one instance must exist per JS runtime, or registration and lookup diverge.

We provide no guarantee that this singleton requirement holds:

  • The install layout — how the package manager dedupes packages in node_modules — decides how many copies exist, and react-native's exact-version pin means third-party ranges never dedupe against it.

Effects:

  • Consumers silently break: expo-asset and expo-image can land on a second copy: assets register in one, resolve as undefined from the other. Expo neutralizes this with a shim in expo/cli that redirects every registry import to a single virtual module — bare React Native + Metro has no such protection.
  • This blocks 1.0: The ecosystem can't move from exact-version lockstep to semver ranges until stateful packages like the asset registry are safe to duplicate. Today, relaxing the pin would turn a latent footgun into a common one.

To solve this, move towards (but not quite yet) deleting react-native/assets-registry, in favour of a replacement AssetRegistry API offered directly by react-native.

Key changes

NOTE: Reviewer note: Browsing file changes on GitHub may be more focused — https://github.com/react/react-native/pull/57369/changes

NOTE: Squash of #57233 (D108750302) and #57232 (D108750303)

'react-native':

  • Add new AssetRegistry API, along with the PackagerAsset and AssetDestPathResolver root type exports in react-native.
  • Add a new 'react-native/asset-registry' secondary entry point — intended for Metro's transformer.assetRegistryPath config contract.

react-native/assets-registry:

  • Update to source from this relocated implementation — fixing the duplicate install layout bug (where apps/frameworks enforce a single copy of react-native).

Impact

  • ✅ Fixed: Imports from either react-native or react-native/assets-registry in RN 0.87+ will be durable to duplicate package installs — Expo can remove their virtual module shim.
  • ✅ Fixed: Deep import 'react-native/Libraries/Image/AssetRegistry' dependency removed (migrated in react-native/metro-config).

Changelog:

  • [General][Fixed] - assets-registry: react-native/assets-registry now shares state across duplicate installs, sourcing from a relocated implementation in the react-native package
  • [General][Added] - Add AssetRegistry API (replaces react-native/assets-registry/registry)
  • [General][Breaking] - react-native/Libraries/Image/AssetRegistry is removed. Please use the AssetRegistry API (apps/library code) and/or the react-native/asset-registry entrypoint (Metro/build configs).

Differential Revision: D109019622

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 29, 2026
@meta-codesync

meta-codesync Bot commented Jun 29, 2026

Copy link
Copy Markdown

@huntie has exported this pull request. If you are a Meta employee, you can view the originating Diff in D109019622.

@github-actions

Copy link
Copy Markdown

Warning

JavaScript API change detected

This PR commits an update to ReactNativeApi.d.ts, indicating a change to React Native's public JavaScript API.

  • Please include a clear changelog message.
  • This change will be subject to additional review.

This change was flagged as: POTENTIALLY_NON_BREAKING


/*::
export type AssetDestPathResolver = 'android' | 'generic';
import {AssetRegistry} from 'react-native';

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Key change 1: Singleton module is located in the typically deduplicated react-native package (both conventionally in the ecosystem and specifically requested in this case by Expo).

transformer: {
allowOptionalDependencies: true,
assetRegistryPath: 'react-native/Libraries/Image/AssetRegistry',
assetRegistryPath: 'react-native/asset-registry',

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Key change 2: Deep Libraries/ import removed, and replaced with our new formal API entry point.

huntie added a commit to huntie/react-native that referenced this pull request Jun 30, 2026
… API (react#57369)

Summary:
Pull Request resolved: react#57369

**Problem**

The separate `react-native/assets-registry` package includes a longstanding ecosystem footgun.

`registry.js` holds asset state in a module-scoped variable, which makes the package a stateful singleton: exactly one instance must exist per JS runtime, or registration and lookup diverge.

We provide no guarantee that this singleton requirement holds:

- The install layout — how the package manager dedupes packages in `node_modules` — decides how many copies exist, and `react-native`'s exact-version pin means third-party ranges never dedupe against it.

Effects:

- **Consumers silently break**: `expo-asset` and `expo-image` can land on a second copy: assets register in one, resolve as `undefined` from the other. Expo neutralizes this with a shim in `expo/cli` that redirects every registry import to a single virtual module — bare React Native + Metro has no such protection.
- **This blocks 1.0**: The ecosystem can't move from exact-version lockstep to semver ranges until stateful packages like the asset registry are safe to duplicate. Today, relaxing the pin would turn a latent footgun into a common one.

**To solve this**, move towards (but not quite yet) deleting `react-native/assets-registry`, in favour of a replacement `AssetRegistry` API offered directly by `react-native`.

**Key changes**

NOTE: **Reviewer note**: Browsing file changes on GitHub may be more focused — https://github.com/react/react-native/pull/57369/changes

NOTE: Squash of react#57233 (D108750302) and react#57232 (D108750303)

`'react-native'`:
- Add new `AssetRegistry` API, along with the `PackagerAsset` and `AssetDestPathResolver` root type exports in `react-native`.
- Add a new `'react-native/asset-registry'` secondary entry point — intended for Metro's `transformer.assetRegistryPath` config contract.

`react-native/assets-registry`:
- Update to source from this relocated implementation — fixing the duplicate install layout bug (where apps/frameworks enforce a single copy of `react-native`).

**Impact**

- **✅ Fixed**: Imports from either `react-native` or `react-native/assets-registry` in RN 0.87+ will be durable to duplicate package installs — Expo can remove their virtual module shim.
- **✅ Fixed**: Deep import `'react-native/Libraries/Image/AssetRegistry'` dependency removed (migrated in `react-native/metro-config`).

Changelog:
- [General][Fixed] - **assets-registry**: `react-native/assets-registry` now shares state across duplicate installs, sourcing from a relocated implementation in the `react-native` package
- [General][Added] - Add `AssetRegistry` API (replaces `react-native/assets-registry/registry`)
- [General][Breaking] - `react-native/Libraries/Image/AssetRegistry` is removed. Please use the `AssetRegistry` API (apps/library code) and/or the `react-native/asset-registry` entrypoint (Metro/build configs).

Differential Revision: D109019622
@meta-codesync meta-codesync Bot changed the title Move AssetRegistry implementation into main package, expose as public API Move AssetRegistry implementation into main package, expose as public API (#57369) Jun 30, 2026
@huntie huntie force-pushed the export-D109019622 branch from d4b8282 to 1d210af Compare June 30, 2026 12:53
huntie added a commit to huntie/react-native that referenced this pull request Jun 30, 2026
… API (react#57369)

Summary:
Pull Request resolved: react#57369

**Problem**

The separate `react-native/assets-registry` package includes a longstanding ecosystem footgun.

`registry.js` holds asset state in a module-scoped variable, which makes the package a stateful singleton: exactly one instance must exist per JS runtime, or registration and lookup diverge.

We provide no guarantee that this singleton requirement holds:

- The install layout — how the package manager dedupes packages in `node_modules` — decides how many copies exist, and `react-native`'s exact-version pin means third-party ranges never dedupe against it.

Effects:

- **Consumers silently break**: `expo-asset` and `expo-image` can land on a second copy: assets register in one, resolve as `undefined` from the other. Expo neutralizes this with a shim in `expo/cli` that redirects every registry import to a single virtual module — bare React Native + Metro has no such protection.
- **This blocks 1.0**: The ecosystem can't move from exact-version lockstep to semver ranges until stateful packages like the asset registry are safe to duplicate. Today, relaxing the pin would turn a latent footgun into a common one.

**To solve this**, move towards (but not quite yet) deleting `react-native/assets-registry`, in favour of a replacement `AssetRegistry` API offered directly by `react-native`.

**Key changes**

NOTE: **Reviewer note**: Browsing file changes on GitHub may be more focused — https://github.com/react/react-native/pull/57369/changes

NOTE: Squash of react#57233 (D108750302) and react#57232 (D108750303)

`'react-native'`:
- Add new `AssetRegistry` API, along with the `PackagerAsset` and `AssetDestPathResolver` root type exports in `react-native`.
- Add a new `'react-native/asset-registry'` secondary entry point — intended for Metro's `transformer.assetRegistryPath` config contract.

`react-native/assets-registry`:
- Update to source from this relocated implementation — fixing the duplicate install layout bug (where apps/frameworks enforce a single copy of `react-native`).

**Impact**

- **✅ Fixed**: Imports from either `react-native` or `react-native/assets-registry` in RN 0.87+ will be durable to duplicate package installs — Expo can remove their virtual module shim.
- **✅ Fixed**: Deep import `'react-native/Libraries/Image/AssetRegistry'` dependency removed (migrated in `react-native/metro-config`).

Changelog:
- [General][Fixed] - **assets-registry**: `react-native/assets-registry` now shares state across duplicate installs, sourcing from a relocated implementation in the `react-native` package
- [General][Added] - Add `AssetRegistry` API (replaces `react-native/assets-registry/registry`)
- [General][Breaking] - `react-native/Libraries/Image/AssetRegistry` is removed. Please use the `AssetRegistry` API (apps/library code) and/or the `react-native/asset-registry` entrypoint (Metro/build configs).

Differential Revision: D109019622
@huntie huntie force-pushed the export-D109019622 branch 2 times, most recently from a79c448 to 534bd79 Compare June 30, 2026 15:50
huntie added a commit to huntie/react-native that referenced this pull request Jun 30, 2026
… API (react#57369)

Summary:
Pull Request resolved: react#57369

**Problem**

The separate `react-native/assets-registry` package includes a longstanding ecosystem footgun.

`registry.js` holds asset state in a module-scoped variable, which makes the package a stateful singleton: exactly one instance must exist per JS runtime, or registration and lookup diverge.

We provide no guarantee that this singleton requirement holds:

- The install layout — how the package manager dedupes packages in `node_modules` — decides how many copies exist, and `react-native`'s exact-version pin means third-party ranges never dedupe against it.

Effects:

- **Consumers silently break**: `expo-asset` and `expo-image` can land on a second copy: assets register in one, resolve as `undefined` from the other. Expo neutralizes this with a shim in `expo/cli` that redirects every registry import to a single virtual module — bare React Native + Metro has no such protection.
- **This blocks 1.0**: The ecosystem can't move from exact-version lockstep to semver ranges until stateful packages like the asset registry are safe to duplicate. Today, relaxing the pin would turn a latent footgun into a common one.

**To solve this**, move towards (but not quite yet) deleting `react-native/assets-registry`, in favour of a replacement `AssetRegistry` API offered directly by `react-native`.

**Key changes**

NOTE: **Reviewer note**: Browsing file changes on GitHub may be more focused — https://github.com/react/react-native/pull/57369/changes

NOTE: Squash of react#57233 (D108750302) and react#57232 (D108750303)

`'react-native'`:
- Add new `AssetRegistry` API, along with the `PackagerAsset` and `AssetDestPathResolver` root type exports in `react-native`.
- Add a new `'react-native/asset-registry'` secondary entry point — intended for Metro's `transformer.assetRegistryPath` config contract.

`react-native/assets-registry`:
- Update to source from this relocated implementation — fixing the duplicate install layout bug (where apps/frameworks enforce a single copy of `react-native`).

**Impact**

- **✅ Fixed**: Imports from either `react-native` or `react-native/assets-registry` in RN 0.87+ will be durable to duplicate package installs — Expo can remove their virtual module shim.
- **✅ Fixed**: Deep import `'react-native/Libraries/Image/AssetRegistry'` dependency removed (migrated in `react-native/metro-config`).

Changelog:
- [General][Fixed] - **assets-registry**: `react-native/assets-registry` now shares state across duplicate installs, sourcing from a relocated implementation in the `react-native` package
- [General][Added] - Add `AssetRegistry` API (replaces `react-native/assets-registry/registry`)
- [General][Breaking] - `react-native/Libraries/Image/AssetRegistry` is removed. Please use the `AssetRegistry` API (apps/library code) and/or the `react-native/asset-registry` entrypoint (Metro/build configs).

Differential Revision: D109019622
huntie added 2 commits June 30, 2026 10:18
Summary:
Pull Request resolved: react#57368

**Context**

This stack intends to relocate the `AssetRegistry` API from `react-native/assets-registry` into `react-native` — addressing runtime safety and public deep imports issues (1.0 and JS Stable API blockers).

**This diff**

Create a new `react-native/asset-utils` package, intended for internal/framework use (read: **will not be an end user concern**). This re-houses `react-native/assets-registry/path-support.js`.

Stacked with the next two diffs, this contributes to the 0.87 objective to delete `react-native/assets-registry` towards install-layout-safe behaviour and JS deep import removal.

- (Temporarily, this leaves two copies of `path-support.js` until I enact the package removal down the stack.)

This change also enables us to de-duplicate `assetPathUtils.js` inside `community-cli-plugin` and use one source of truth.

- Additionally, we have fbsource consumers of this util that cannot have a circular Buck dep on `react-native`, so the main package was not a suitable relocation point (secondarily to not adding an awkward new public API here).

**Changes**
- Add `react-native/asset-utils` (`packages/asset-utils/`): `src/AssetPathUtils.js` containing Android path helpers and tests.
- De-duplicate usages in `community-cli-plugin`: delete `src/commands/bundle/assetPathUtils.js`.

Changelog:
[General][Added] - Introduce `react-native/asset-utils` package (relocates Android path utils for libraries/frameworks)

Differential Revision: D110045272
… API (react#57369)

Summary:
Pull Request resolved: react#57369

**Problem**

The separate `react-native/assets-registry` package includes a longstanding ecosystem footgun.

`registry.js` holds asset state in a module-scoped variable, which makes the package a stateful singleton: exactly one instance must exist per JS runtime, or registration and lookup diverge.

We provide no guarantee that this singleton requirement holds:

- The install layout — how the package manager dedupes packages in `node_modules` — decides how many copies exist, and `react-native`'s exact-version pin means third-party ranges never dedupe against it.

Effects:

- **Consumers silently break**: `expo-asset` and `expo-image` can land on a second copy: assets register in one, resolve as `undefined` from the other. Expo neutralizes this with a shim in `expo/cli` that redirects every registry import to a single virtual module — bare React Native + Metro has no such protection.
- **This blocks 1.0**: The ecosystem can't move from exact-version lockstep to semver ranges until stateful packages like the asset registry are safe to duplicate. Today, relaxing the pin would turn a latent footgun into a common one.

**To solve this**, move towards (but not quite yet) deleting `react-native/assets-registry`, in favour of a replacement `AssetRegistry` API offered directly by `react-native`.

**Key changes**

NOTE: **Reviewer note**: Browsing file changes on GitHub may be more focused — https://github.com/react/react-native/pull/57369/changes

NOTE: Squash of react#57233 (D108750302) and react#57232 (D108750303)

`'react-native'`:
- Add new `AssetRegistry` API, along with the `PackagerAsset` and `AssetDestPathResolver` root type exports in `react-native`.
- Add a new `'react-native/asset-registry'` secondary entry point — intended for Metro's `transformer.assetRegistryPath` config contract.

`react-native/assets-registry`:
- Update to source from this relocated implementation — fixing the duplicate install layout bug (where apps/frameworks enforce a single copy of `react-native`).

**Impact**

- **✅ Fixed**: Imports from either `react-native` or `react-native/assets-registry` in RN 0.87+ will be durable to duplicate package installs — Expo can remove their virtual module shim.
- **✅ Fixed**: Deep import `'react-native/Libraries/Image/AssetRegistry'` dependency removed (migrated in `react-native/metro-config`).

Changelog:
- [General][Fixed] - **assets-registry**: `react-native/assets-registry` now shares state across duplicate installs, sourcing from a relocated implementation in the `react-native` package
- [General][Added] - Add `AssetRegistry` API (replaces `react-native/assets-registry/registry`)
- [General][Breaking] - `react-native/Libraries/Image/AssetRegistry` is removed. Please use the `AssetRegistry` API (apps/library code) and/or the `react-native/asset-registry` entrypoint (Metro/build configs).

Differential Revision: D109019622
@huntie huntie force-pushed the export-D109019622 branch from 534bd79 to a347134 Compare June 30, 2026 17:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant