Skip to content

fix: remove deep imports from 'react-native' - #18

Merged
V3RON merged 1 commit into
mainfrom
fix/remove-react-native-deep-imports
Aug 31, 2026
Merged

fix: remove deep imports from 'react-native'#18
V3RON merged 1 commit into
mainfrom
fix/remove-react-native-deep-imports

Conversation

@V3RON

@V3RON V3RON commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Closes #17.

React Native 0.80 deprecated deep imports from react-native/Libraries/*, and 0.87 enables the Strict TypeScript API by default, which blocks them at the type level. We imported two internal modules, which produced deprecation warnings in every consumer app:

WARN  Deep imports from the 'react-native' package are deprecated
('react-native/Libraries/Core/Devtools/getDevServer').
Source: .../dist/esm/react-native/copy.js

Checked against the published react-native@0.87.1 tarball: ./Libraries/* still resolves at runtime ("default": "./Libraries/*.js") but its types entry is now null, and the react-native-legacy-deep-imports opt-out is scheduled for removal in 0.88. So Libraries/ is now explicitly outside the API contract — Meta can relocate these files in any release without it counting as breaking.

What changed

Both modules are reimplemented locally on top of React Native's public API:

src/react-native/dev-server.ts — derives the Metro origin from NativeModules.SourceCode.getConstants().scriptURL, with the same caching and http://localhost:8081/ fallback semantics as upstream. NativeModules is a public root export of the Strict API (types_generated/index.d.ts:123). Falls back to sourceCode.scriptURL for older React Native versions that expose it as a plain constant, and tolerates the module throwing or being absent.

src/react-native/symbolicate.ts — posts directly to Metro's symbolicate endpoint with {stack, extraData}. That is all the upstream module did, and we already hand-roll its siblings (open-stack-frame in open.ts, /__react-native-grab/copy in copy.ts).

open.ts, copy.ts, and get-rendered-by.ts now point at these. The ambient declare module "react-native/Libraries/Core/Devtools/getDevServer" shim in get-dev-server.d.ts is deleted — nothing needs it anymore.

Why not unstable-internals-do-not-use

0.87 added react-native/unstable-internals-do-not-use as a sanctioned compatibility bridge for libraries in exactly this position. It was the obvious candidate, but it does not fit:

  • it exports getDevServer but not symbolicateStackTrace, so it only solves half the problem;
  • it requires every consumer to add "customConditions": ["react-native-unstable-internals"] to their tsconfig for types to resolve — a bad ask for a library;
  • it does not exist before 0.87, so we would need a fallback path anyway.

There is also no globalThis escape hatch — the only relevant global in 0.87.1 is global.__METRO_GLOBAL_PREFIX__ + '__loadBundleAsync', which does not expose the dev server URL.

Result

Zero deep imports, zero warnings, no consumer tsconfig requirement, and support across all React Native versions including pre-0.87. Verified on the built output:

$ grep -rE "(from|require\()\s*['\"]react-native/" dist/
NO deep import statements in dist

Testing

8 new unit tests covering scriptURL parsing, the localhost fallback for release bundles, the legacy plain-constant path, a throwing native module, caching, the symbolicate request shape, the not-loaded-from-Metro guard, and error statuses.

npm test 26 passed · npm run lint clean · npm run build clean.

https://claude.ai/code/session_01KDiabfZtYE2vxCeybZnA4D

React Native 0.80 deprecated deep imports from `react-native/Libraries/*`,
and 0.87 enables the Strict TypeScript API by default, which blocks them at
the type level. `./Libraries/*` still resolves at runtime, but it is now
explicitly outside the public API contract.

Replace both internal modules with local implementations built on the public
API:

- `dev-server.ts` derives the Metro origin from
  `NativeModules.SourceCode.getConstants().scriptURL`, matching upstream's
  cache and localhost fallback semantics. `NativeModules` is a public root
  export of the Strict API.
- `symbolicate.ts` posts directly to Metro's `symbolicate` endpoint, which is
  all the upstream module did.

The alternative, `react-native/unstable-internals-do-not-use`, exports
`getDevServer` but not `symbolicateStackTrace`, requires consumers to set a
`customConditions` entry in their tsconfig, and does not exist before 0.87.

Also drops the now-unneeded ambient `declare module` shim.

Closes #17

Claude-Session: https://claude.ai/code/session_01KDiabfZtYE2vxCeybZnA4D
@V3RON
V3RON merged commit 10a173c into main Aug 31, 2026
4 checks passed
@V3RON
V3RON deleted the fix/remove-react-native-deep-imports branch August 31, 2026 15:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove deep imports from 'react-native' (Strict API is default in 0.87)

1 participant