fix(react-native): fix unable to resolve realm (#26983)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes https://github.com/nrwl/nx/issues/26853
This commit is contained in:
Emily Xiong 2024-07-19 12:25:45 -07:00 committed by GitHub
parent b623104aac
commit e87bf395e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 120 additions and 24 deletions

View File

@ -13,7 +13,11 @@ import { workspaceRoot } from '@nx/devkit';
* This resolve function requires projectRoot to be set to * This resolve function requires projectRoot to be set to
* workspace root in order modules and assets to be registered and watched. * workspace root in order modules and assets to be registered and watched.
*/ */
export function getResolveRequest(extensions: string[]) { export function getResolveRequest(
extensions: string[],
exportsConditionNames: string[] = [],
mainFields: string[] = []
) {
return function ( return function (
_context: any, _context: any,
realModuleName: string, realModuleName: string,
@ -21,8 +25,6 @@ export function getResolveRequest(extensions: string[]) {
) { ) {
const debug = process.env.NX_REACT_NATIVE_DEBUG === 'true'; const debug = process.env.NX_REACT_NATIVE_DEBUG === 'true';
if (debug) console.log(chalk.cyan(`[Nx] Resolving: ${realModuleName}`));
const { resolveRequest, ...context } = _context; const { resolveRequest, ...context } = _context;
const resolvedPath = const resolvedPath =
@ -32,16 +34,23 @@ export function getResolveRequest(extensions: string[]) {
realModuleName, realModuleName,
platform, platform,
debug debug
) || ) ??
defaultMetroResolver(context, realModuleName, platform, debug) || defaultMetroResolver(context, realModuleName, platform, debug) ??
tsconfigPathsResolver( tsconfigPathsResolver(
context, context,
extensions, extensions,
realModuleName, realModuleName,
platform, platform,
debug debug
) || ) ??
pnpmResolver(extensions, context, realModuleName, debug); pnpmResolver(
extensions,
context,
realModuleName,
debug,
exportsConditionNames,
mainFields
);
if (resolvedPath) { if (resolvedPath) {
return resolvedPath; return resolvedPath;
} }
@ -104,7 +113,9 @@ function pnpmResolver(
extensions: string[], extensions: string[],
context: any, context: any,
realModuleName: string, realModuleName: string,
debug: boolean debug: boolean,
exportsConditionNames: string[] = [],
mainFields: string[] = []
) { ) {
try { try {
const pnpmResolve = getPnpmResolver(extensions); const pnpmResolve = getPnpmResolver(extensions);
@ -199,7 +210,11 @@ function getMatcher(debug: boolean) {
* It is inspired form https://github.com/vjpr/pnpm-expo-example/blob/main/packages/pnpm-expo-helper/util/make-resolver.js. * It is inspired form https://github.com/vjpr/pnpm-expo-example/blob/main/packages/pnpm-expo-helper/util/make-resolver.js.
*/ */
let resolver; let resolver;
function getPnpmResolver(extensions: string[]) { function getPnpmResolver(
extensions: string[],
exportsConditionNames: string[] = [],
mainFields: string[] = []
) {
if (!resolver) { if (!resolver) {
const fileSystem = new CachedInputFileSystem(fs, 4000); const fileSystem = new CachedInputFileSystem(fs, 4000);
resolver = ResolverFactory.createResolver({ resolver = ResolverFactory.createResolver({
@ -207,8 +222,16 @@ function getPnpmResolver(extensions: string[]) {
extensions: extensions.map((extension) => '.' + extension), extensions: extensions.map((extension) => '.' + extension),
useSyncFileSystemCalls: true, useSyncFileSystemCalls: true,
modules: [join(workspaceRoot, 'node_modules'), 'node_modules'], modules: [join(workspaceRoot, 'node_modules'), 'node_modules'],
conditionNames: ['native', 'browser', 'require', 'default'], conditionNames: [
mainFields: ['react-native', 'browser', 'main'], 'native',
'browser',
'require',
'default',
'react-native',
'node',
...exportsConditionNames,
],
mainFields: ['react-native', 'browser', 'main', ...mainFields],
aliasFields: ['browser'], aliasFields: ['browser'],
}); });
} }

View File

@ -7,9 +7,30 @@ import { join } from 'path';
import { getResolveRequest } from './metro-resolver'; import { getResolveRequest } from './metro-resolver';
interface WithNxOptions { interface WithNxOptions {
/**
* Change this to true to see debugging info.
*/
debug?: boolean; debug?: boolean;
/**
* A list of additional file extensions to resolve
* All the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
*/
extensions?: string[]; extensions?: string[];
/**
* A list of additional folders to watch for changes
* By default, it watches all the folders in the workspace root except 'dist' and 'e2e'
*/
watchFolders?: string[]; watchFolders?: string[];
/*
* A list of exports field condition names in node_modules libraries' package.json
* If a library has a package.json with an exports field, but it can't be resolved with the default conditions, you can add the name of the condition to this list.
*/
exportsConditionNames?: string[];
/**
* A list of main fields in package.json files to use for resolution
* If a library has a package.json with a main field that can't be resolved with the default conditions, you can add the name of the field to this list.
*/
mainFields?: string[];
} }
export async function withNxMetro( export async function withNxMetro(
@ -38,7 +59,11 @@ export async function withNxMetro(
const nxConfig: MetroConfig = { const nxConfig: MetroConfig = {
resolver: { resolver: {
resolveRequest: getResolveRequest(extensions), resolveRequest: getResolveRequest(
extensions,
opts.exportsConditionNames,
opts.mainFields
),
nodeModulesPaths: [join(workspaceRoot, 'node_modules')], nodeModulesPaths: [join(workspaceRoot, 'node_modules')],
}, },
watchFolders, watchFolders,

View File

@ -13,7 +13,11 @@ import { workspaceRoot } from '@nx/devkit';
* This resolve function requires projectRoot to be set to * This resolve function requires projectRoot to be set to
* workspace root in order modules and assets to be registered and watched. * workspace root in order modules and assets to be registered and watched.
*/ */
export function getResolveRequest(extensions: string[]) { export function getResolveRequest(
extensions: string[],
exportsConditionNames: string[] = [],
mainFields: string[] = []
) {
return function ( return function (
_context: any, _context: any,
realModuleName: string, realModuleName: string,
@ -21,8 +25,6 @@ export function getResolveRequest(extensions: string[]) {
) { ) {
const debug = process.env.NX_REACT_NATIVE_DEBUG === 'true'; const debug = process.env.NX_REACT_NATIVE_DEBUG === 'true';
if (debug) console.log(chalk.cyan(`[Nx] Resolving: ${realModuleName}`));
const { resolveRequest, ...context } = _context; const { resolveRequest, ...context } = _context;
const resolvedPath = const resolvedPath =
@ -32,16 +34,23 @@ export function getResolveRequest(extensions: string[]) {
realModuleName, realModuleName,
platform, platform,
debug debug
) || ) ??
defaultMetroResolver(context, realModuleName, platform, debug) || defaultMetroResolver(context, realModuleName, platform, debug) ??
tsconfigPathsResolver( tsconfigPathsResolver(
context, context,
extensions, extensions,
realModuleName, realModuleName,
platform, platform,
debug debug
) || ) ??
pnpmResolver(extensions, context, realModuleName, debug); pnpmResolver(
extensions,
context,
realModuleName,
debug,
exportsConditionNames,
mainFields
);
if (resolvedPath) { if (resolvedPath) {
return resolvedPath; return resolvedPath;
} }
@ -104,7 +113,9 @@ function pnpmResolver(
extensions: string[], extensions: string[],
context: any, context: any,
realModuleName: string, realModuleName: string,
debug: boolean debug: boolean,
exportsConditionNames: string[] = [],
mainFields: string[] = []
) { ) {
try { try {
const pnpmResolve = getPnpmResolver(extensions); const pnpmResolve = getPnpmResolver(extensions);
@ -199,7 +210,11 @@ function getMatcher(debug: boolean) {
* It is inspired form https://github.com/vjpr/pnpm-expo-example/blob/main/packages/pnpm-expo-helper/util/make-resolver.js. * It is inspired form https://github.com/vjpr/pnpm-expo-example/blob/main/packages/pnpm-expo-helper/util/make-resolver.js.
*/ */
let resolver; let resolver;
function getPnpmResolver(extensions: string[]) { function getPnpmResolver(
extensions: string[],
exportsConditionNames: string[] = [],
mainFields: string[] = []
) {
if (!resolver) { if (!resolver) {
const fileSystem = new CachedInputFileSystem(fs, 4000); const fileSystem = new CachedInputFileSystem(fs, 4000);
resolver = ResolverFactory.createResolver({ resolver = ResolverFactory.createResolver({
@ -207,8 +222,16 @@ function getPnpmResolver(extensions: string[]) {
extensions: extensions.map((extension) => '.' + extension), extensions: extensions.map((extension) => '.' + extension),
useSyncFileSystemCalls: true, useSyncFileSystemCalls: true,
modules: [join(workspaceRoot, 'node_modules'), 'node_modules'], modules: [join(workspaceRoot, 'node_modules'), 'node_modules'],
conditionNames: ['native', 'browser', 'require', 'default'], conditionNames: [
mainFields: ['react-native', 'browser', 'main'], 'native',
'browser',
'require',
'default',
'react-native',
'node',
...exportsConditionNames,
],
mainFields: ['react-native', 'browser', 'main', ...mainFields],
aliasFields: ['browser'], aliasFields: ['browser'],
}); });
} }

View File

@ -7,9 +7,30 @@ import { join } from 'path';
import { getResolveRequest } from './metro-resolver'; import { getResolveRequest } from './metro-resolver';
interface WithNxOptions { interface WithNxOptions {
/**
* Change this to true to see debugging info.
*/
debug?: boolean; debug?: boolean;
/**
* A list of additional file extensions to resolve
* All the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
*/
extensions?: string[]; extensions?: string[];
/**
* A list of additional folders to watch for changes
* By default, it watches all the folders in the workspace root except 'dist' and 'e2e'
*/
watchFolders?: string[]; watchFolders?: string[];
/*
* A list of exports field condition names in node_modules libraries' package.json
* If a library has a package.json with an exports field, but it can't be resolved with the default conditions, you can add the name of the condition to this list.
*/
exportsConditionNames?: string[];
/**
* A list of main fields in package.json files to use for resolution
* If a library has a package.json with a main field that can't be resolved with the default conditions, you can add the name of the field to this list.
*/
mainFields?: string[];
} }
export async function withNxMetro( export async function withNxMetro(
@ -38,7 +59,11 @@ export async function withNxMetro(
const nxConfig: MetroConfig = { const nxConfig: MetroConfig = {
resolver: { resolver: {
resolveRequest: getResolveRequest(extensions), resolveRequest: getResolveRequest(
extensions,
opts.exportsConditionNames,
opts.mainFields
),
nodeModulesPaths: [join(workspaceRoot, 'node_modules')], nodeModulesPaths: [join(workspaceRoot, 'node_modules')],
}, },
watchFolders, watchFolders,