rnx-kit
rnx-kit copied to clipboard
Update Metro types in response to breaking changes in Metro's `resolver` configuration property
Background
@react-native-community/cli 8 moved from Metro 0.67 to 0.70. This brought in a breaking change from Metro. They changed the context
parameter that is passed to the optional custom module resolver in Metro config (resolver
property).
The context
param (first argument) had previously been a read/write object with a resolveRequest
property set to whatever custom resolver was in place (the function pointed to by resolver
). When Metro made the call out to the custom resolver, it wouldn't change resolveRequest
.
Our code has custom resolvers, and they sometimes need to call back into Metro to get the "default" resolution behavior. Metro needs the context
, so to avoid infinite recursion, we would unhook resolveRequest
from context and then put it back later.
With the breaking change from Metro, two things happened -- (i) context
became a frozen (read-only) object, and (ii) the recursion detection was changed, effectively doing what we did by replacing resolveRequest
before invoking any custom resolver.
Our code can no longer unhook and replace resolveRequest
. JS will fail with a TypeError. To be compatible with old and new versions of Metro, we need to detect if resolveRequest
is pointing at our resolver or Metro's resolver, and adjust as needed by making a copy of context rather than modifying it.
Timeline
Metro made this breaking change on 1/31/2022: https://github.com/facebook/metro/commit/d81d8877c05637eac2b4ea946a9fa1e8ae869b06. It shipped in version 0.68.
@react-native-community/cli updated from Metro 0.67 to 0.70 on 5/4/2022: https://github.com/react-native-community/cli/commit/65c5d02cd82704a0c0e78841d65f7da98db19342. This updated shipped in v8.0.0-alpha.5.
@react-native-community/cli-plugin-metro broke when alpha.5 was made, and was fixed in alpha.6 on 5/10/2022: https://github.com/react-native-community/cli/pull/1605.
RN 0.68.2, released yesterday, is still on Metro 0.67.x / CLI 7.x. RN 0.69-stable is on Metro 0.70.x and CLI 8.x, which means @rnx-kit customers going to RN 0.69 will break.
RN 0.69 is currently in the RC phase of being released as of 5/10/2022. It will be releasing soon (days, not weeks).
Proposed Fix
We have 2 packages which are impacted by these changes: @rnx-kit/metro-resolver-symlinks and @rnx-kit/metro-service.
@rnx-kit/metro-resolver-symlinks
src/index.ts: makeResolver()
: Lift the anonymous arrow function out into a global function. Add logic to detect whether resolveRequest
points to the global function, or Metro's resolve()
function (from getMetroResolver()
). If it points to ours, replace context
with a copy of itself, setting resolveRequest
to Metro's function.
@rnx-kit/metro-service
src/config.ts: reactNativePlatformResolver()
: This code was copied from the CLI, before cli-plugin-metro was available to consume and use as its own package. I'd like to retire this logic, and use cli-plugin-metro, but we need to support a broad range of RN/CLI/Metro builds, spanning before and after this break. So, we should fix this the same way it was fixed in the CLI -- https://github.com/react-native-community/cli/commit/65c5d02cd82704a0c0e78841d65f7da98db19342.
cc: @tido64 @kelset
It will be releasing soon (days, not weeks).
quick note, it will be weeks before RN 0.69 reached 0.69.0. What will land soon is the next RC.
Before we close this issue, we should also update the types: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/3625f7e63f834d0e37aa062127a903ca1ce8a3b8/types/metro-resolver/types.d.ts#L104-L109
(I didn't even realise that there are metro types on DT.. we probably need to fit those in the RN+TS conversation 🤦♂️)
Types are being updated here: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/64735