From 39988a681a1c289e9dbfde4902343b59a036ae81 Mon Sep 17 00:00:00 2001 From: Dmytro Rykun Date: Mon, 18 Dec 2023 06:09:25 -0800 Subject: [PATCH] Introduce "codegenConfig.includesGeneratedCode" property (#41655) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/41655 This diff adds support for checked-in codegen artifacts for libraries. It introduces a new property to `codegenConfig`, called `includesGeneratedCode`. If codegen sees `includesGeneratedCode: true` in a project's dependency, it assumes that the library has codegen artifacts in it, and will not generate any code. Changelog: [General][Added] - Introduce "codegenConfig.includesGeneratedCode" property. Differential Revision: D51207265 Reviewed By: cipolleschi fbshipit-source-id: 5f6822714005c7eb5ee8019f3691d8d79f9d2b66 --- .../kotlin/com/facebook/react/ReactPlugin.kt | 8 +++- .../codegen/generate-artifacts-executor.js | 48 +++++++++++++++---- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt index 5709501f3b594e..469840eee6471b 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactPlugin.kt @@ -161,6 +161,7 @@ class ReactPlugin : Plugin { val parsedPackageJson = packageJson?.let { JsonUtils.fromPackageJson(it) } val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir + val includesGeneratedCode = parsedPackageJson?.codegenConfig?.includesGeneratedCode if (jsSrcsDirInPackageJson != null) { it.jsRootDir.set(File(packageJson.parentFile, jsSrcsDirInPackageJson)) } else { @@ -168,7 +169,7 @@ class ReactPlugin : Plugin { } val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root) - it.onlyIf { isLibrary || needsCodegenFromPackageJson } + it.onlyIf { (isLibrary || needsCodegenFromPackageJson) && !includesGeneratedCode } } // We create the task to generate Java code from schema. @@ -188,7 +189,10 @@ class ReactPlugin : Plugin { // Therefore, the appNeedsCodegen needs to be invoked inside this lambda. val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root) - it.onlyIf { isLibrary || needsCodegenFromPackageJson } + val packageJson = findPackageJsonFile(project, rootExtension.root) + val parsedPackageJson = packageJson?.let { JsonUtils.fromPackageJson(it) } + val includesGeneratedCode = parsedPackageJson?.codegenConfig?.includesGeneratedCode + it.onlyIf { (isLibrary || needsCodegenFromPackageJson) && !includesGeneratedCode } } // We update the android configuration to include the generated sources. diff --git a/packages/react-native/scripts/codegen/generate-artifacts-executor.js b/packages/react-native/scripts/codegen/generate-artifacts-executor.js index 2ebfac679b592c..33471eef4d8e79 100644 --- a/packages/react-native/scripts/codegen/generate-artifacts-executor.js +++ b/packages/react-native/scripts/codegen/generate-artifacts-executor.js @@ -41,6 +41,10 @@ const REACT_NATIVE = 'react-native'; // HELPERS +function includesGeneratedCode(pkgJson) { + return pkgJson.codegenConfig && pkgJson.codegenConfig.includesGeneratedCode; +} + function isReactNativeCoreLibrary(libraryName) { return libraryName in CORE_LIBRARIES_WITH_OUTPUT_FOLDER; } @@ -195,7 +199,12 @@ function computeOutputPath(projectRoot, baseOutputPath, pkgJson) { baseOutputPath = projectRoot; } } - return path.join(baseOutputPath, 'build', 'generated', 'ios'); + if (includesGeneratedCode(pkgJson)) { + // Don't create nested directories for libraries to make importing generated headers easier. + return baseOutputPath; + } else { + return path.join(baseOutputPath, 'build', 'generated', 'ios'); + } } function generateSchemaInfo(library) { @@ -260,6 +269,16 @@ function needsThirdPartyComponentProvider(schemaInfo) { return !isReactNativeCoreLibrary(schemaInfo.library.config.name); } +function mustGenerateNativeCode(includeLibraryPath, schemaInfo) { + // If library's 'codegenConfig' sets 'includesGeneratedCode' to 'true', + // then we assume that native code is shipped with the library, + // and we don't need to generate it. + return ( + schemaInfo.library.libraryPath === includeLibraryPath || + !schemaInfo.library.config.includesGeneratedCode + ); +} + function createComponentProvider(schemas) { console.log('\n\n>>>>> Creating component provider'); const outputDir = path.join( @@ -281,10 +300,12 @@ function createComponentProvider(schemas) { } function findCodegenEnabledLibraries(pkgJson, projectRoot) { - return [ - ...findExternalLibraries(pkgJson), - ...findProjectRootLibraries(pkgJson, projectRoot), - ]; + const projectLibraries = findProjectRootLibraries(pkgJson, projectRoot); + if (includesGeneratedCode(pkgJson)) { + return projectLibraries; + } else { + return [...projectLibraries, ...findExternalLibraries(pkgJson)]; + } } // It removes all the empty files and empty folders @@ -355,12 +376,19 @@ function execute(projectRoot, baseOutputPath) { const outputPath = computeOutputPath(projectRoot, baseOutputPath, pkgJson); const schemaInfos = generateSchemaInfos(libraries); - generateNativeCode(outputPath, schemaInfos); + generateNativeCode( + outputPath, + schemaInfos.filter(schemaInfo => + mustGenerateNativeCode(projectRoot, schemaInfo), + ), + ); - const schemas = schemaInfos - .filter(needsThirdPartyComponentProvider) - .map(schemaInfo => schemaInfo.schema); - createComponentProvider(schemas); + if (!includesGeneratedCode(pkgJson)) { + const schemas = schemaInfos + .filter(needsThirdPartyComponentProvider) + .map(schemaInfo => schemaInfo.schema); + createComponentProvider(schemas); + } cleanupEmptyFilesAndFolders(outputPath); } catch (err) { console.error(err);