From bb73315a3fd8cd203c4ddb3ffa10bfec307c7e92 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Wed, 3 Sep 2025 05:34:11 -0700 Subject: [PATCH] Use autolinking react-native-config output in iOS artifacts generator (#53503) Summary: Resolves https://github.com/facebook/react-native/issues/53501 This is a pretty major oversight of (presumably) the old autolinking refactor. The iOS autolinking's second stage, invoked in `use_react_native!` does not accept the `react-native-config` sub-command's `react-native-config` output. This is only invoked and used in the prior step, `use_native_modules`. The second step instead invokes old code that does something _similar_ to the new autolinking in `scripts/generate-artifacts-executor`, and happens to align in most cases. (But it does "autolinking" from scratch). tl;dr: When the results don't match up, things go wrong. Instead, we now write the autolinking (react native config) results to a file, then read the output back in the second step. This doesn't affect Android/Gradle, which are implemented correctly. [IOS] [FIXED] - Use autolinking-generated react-native-config output in second step of cocoapods linking that generates artifacts and generated source Pull Request resolved: https://github.com/facebook/react-native/pull/53503 Test Plan: - See https://github.com/facebook/react-native/issues/53501 for failing repro - Clone for working repro: https://github.com/byCedric/react-native-codegen-ios-autolinking/tree/fix-54503 - Note: Contains this PR's changes as a patch - `bun install` - `bun expo run:ios` Reviewed By: cortinico Differential Revision: D81490755 Pulled By: cipolleschi fbshipit-source-id: eefe786a116404f4ed24bd7125dfb108a811f71e --- .../scripts/cocoapods/autolinking.rb | 6 +++ .../scripts/cocoapods/codegen_utils.rb | 2 +- .../generate-artifacts-executor/index.js | 6 ++- .../generate-artifacts-executor/utils.js | 51 +++++++++++++++---- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/packages/react-native/scripts/cocoapods/autolinking.rb b/packages/react-native/scripts/cocoapods/autolinking.rb index b2e5600bc5d..d8e9c7cec2f 100644 --- a/packages/react-native/scripts/cocoapods/autolinking.rb +++ b/packages/react-native/scripts/cocoapods/autolinking.rb @@ -40,6 +40,12 @@ def list_native_modules!(config_command) packages = config["dependencies"] ios_project_root = Pathname.new(config["project"]["ios"]["sourceDir"]) react_native_path = Pathname.new(config["reactNativePath"]) + codegen_output_path = ios_project_root.join("build/generated/autolinking/autolinking.json") + + # Write autolinking react-native-config output to codegen folder + FileUtils.mkdir_p(File.dirname(codegen_output_path)) + File.write(codegen_output_path, json) + found_pods = [] packages.each do |package_name, package| diff --git a/packages/react-native/scripts/cocoapods/codegen_utils.rb b/packages/react-native/scripts/cocoapods/codegen_utils.rb index 3ce12e28ebc..3c51ad584e1 100644 --- a/packages/react-native/scripts/cocoapods/codegen_utils.rb +++ b/packages/react-native/scripts/cocoapods/codegen_utils.rb @@ -87,7 +87,7 @@ class CodegenUtils codegen_path = file_manager.join(ios_folder, codegen_dir) return if !dir_manager.exist?(codegen_path) - FileUtils.rm_rf(dir_manager.glob("#{codegen_path}/*")) + FileUtils.rm_rf("#{codegen_path}") base_provider_path = file_manager.join(rn_path, 'React', 'Fabric', 'RCTThirdPartyFabricComponentsProvider') FileUtils.rm_rf("#{base_provider_path}.h") FileUtils.rm_rf("#{base_provider_path}.mm") diff --git a/packages/react-native/scripts/codegen/generate-artifacts-executor/index.js b/packages/react-native/scripts/codegen/generate-artifacts-executor/index.js index 002273410bd..a3c52e39f38 100644 --- a/packages/react-native/scripts/codegen/generate-artifacts-executor/index.js +++ b/packages/react-native/scripts/codegen/generate-artifacts-executor/index.js @@ -86,10 +86,14 @@ function execute( buildCodegenIfNeeded(); } - const reactNativeConfig = readReactNativeConfig(projectRoot); + const reactNativeConfig = readReactNativeConfig( + projectRoot, + baseOutputPath, + ); const codegenEnabledLibraries = findCodegenEnabledLibraries( pkgJson, projectRoot, + baseOutputPath, reactNativeConfig, ); diff --git a/packages/react-native/scripts/codegen/generate-artifacts-executor/utils.js b/packages/react-native/scripts/codegen/generate-artifacts-executor/utils.js index db611c8db17..f2fa2fc852f 100644 --- a/packages/react-native/scripts/codegen/generate-artifacts-executor/utils.js +++ b/packages/react-native/scripts/codegen/generate-artifacts-executor/utils.js @@ -97,15 +97,40 @@ function cleanupEmptyFilesAndFolders(filepath /*: string */) { } } -function readReactNativeConfig(projectRoot /*: string */) /*: $FlowFixMe */ { - const rnConfigFilePath = path.resolve(projectRoot, 'react-native.config.js'); +function readGeneratedAutolinkingOutput( + baseOutputPath /*: string */, +) /*: $FlowFixMe */ { + // NOTE: Generated by scripts/cocoapods/autolinking.rb in list_native_modules (called by use_native_modules) + const autolinkingGeneratedPath = path.resolve( + baseOutputPath, + 'build/generated/autolinking/autolinking.json', + ); + if (fs.existsSync(autolinkingGeneratedPath)) { + // $FlowFixMe[unsupported-syntax] + return require(autolinkingGeneratedPath); + } else { + codegenLog( + `Could not find generated autolinking output at: ${autolinkingGeneratedPath}`, + ); + return null; + } +} - if (!fs.existsSync(rnConfigFilePath)) { +function readReactNativeConfig( + projectRoot /*: string */, + baseOutputPath /*: string */, +) /*: $FlowFixMe */ { + const autolinkingOutput = readGeneratedAutolinkingOutput(baseOutputPath); + const rnConfigFilePath = path.resolve(projectRoot, 'react-native.config.js'); + if (autolinkingOutput) { + return autolinkingOutput; + } else if (fs.existsSync(rnConfigFilePath)) { + // $FlowIgnore[unsupported-syntax] + return require(rnConfigFilePath); + } else { + codegenLog(`Could not find React Native config at: ${rnConfigFilePath}`); return {}; } - - // $FlowIgnore[unsupported-syntax] - return require(rnConfigFilePath); } /** @@ -114,17 +139,23 @@ function readReactNativeConfig(projectRoot /*: string */) /*: $FlowFixMe */ { function findCodegenEnabledLibraries( pkgJson /*: $FlowFixMe */, projectRoot /*: string */, + baseOutputPath /*: string */, reactNativeConfig /*: $FlowFixMe */, ) /*: Array<$FlowFixMe> */ { const projectLibraries = findProjectRootLibraries(pkgJson, projectRoot); if (pkgJsonIncludesGeneratedCode(pkgJson)) { return projectLibraries; } else { - return [ - ...projectLibraries, - ...findExternalLibraries(pkgJson, projectRoot), + const libraries = [...projectLibraries]; + // If we ran autolinking, we shouldn't try to run our own "autolinking-like" + // library discovery + if (!readGeneratedAutolinkingOutput(baseOutputPath)) { + libraries.push(...findExternalLibraries(pkgJson, projectRoot)); + } + libraries.push( ...findLibrariesFromReactNativeConfig(projectRoot, reactNativeConfig), - ]; + ); + return libraries; } }