From 21784e2ce5dbf361511a77e9546c8839321e5b74 Mon Sep 17 00:00:00 2001 From: Dmitry Rykun Date: Tue, 19 Dec 2023 05:28:01 -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. Reviewed By: cipolleschi Differential Revision: D51207265 fbshipit-source-id: 65855fd846e24a53cb18008839121e99eeb59309 --- .../kotlin/com/facebook/react/ReactPlugin.kt | 10 +++- .../react/model/ModelCodegenConfig.kt | 3 +- .../codegen/generate-artifacts-executor.js | 48 +++++++++++++++---- 3 files changed, 48 insertions(+), 13 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..2c5bea4099c53f 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,8 @@ class ReactPlugin : Plugin { val parsedPackageJson = packageJson?.let { JsonUtils.fromPackageJson(it) } val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir + val includesGeneratedCode = + parsedPackageJson?.codegenConfig?.includesGeneratedCode ?: false if (jsSrcsDirInPackageJson != null) { it.jsRootDir.set(File(packageJson.parentFile, jsSrcsDirInPackageJson)) } else { @@ -168,7 +170,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 +190,11 @@ 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 ?: false + it.onlyIf { (isLibrary || needsCodegenFromPackageJson) && !includesGeneratedCode } } // We update the android configuration to include the generated sources. diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/model/ModelCodegenConfig.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/model/ModelCodegenConfig.kt index 26d7f08d95d3c7..afd02bc06ab490 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/model/ModelCodegenConfig.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/model/ModelCodegenConfig.kt @@ -11,5 +11,6 @@ data class ModelCodegenConfig( val name: String?, val type: String?, val jsSrcsDir: String?, - val android: ModelCodegenConfigAndroid? + val android: ModelCodegenConfigAndroid?, + val includesGeneratedCode: Boolean?, ) diff --git a/packages/react-native/scripts/codegen/generate-artifacts-executor.js b/packages/react-native/scripts/codegen/generate-artifacts-executor.js index 2ebfac679b592c..9d46fd55b6d511 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 pkgJsonIncludesGeneratedCode(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 (pkgJsonIncludesGeneratedCode(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 (pkgJsonIncludesGeneratedCode(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 (!pkgJsonIncludesGeneratedCode(pkgJson)) { + const schemas = schemaInfos + .filter(needsThirdPartyComponentProvider) + .map(schemaInfo => schemaInfo.schema); + createComponentProvider(schemas); + } cleanupEmptyFilesAndFolders(outputPath); } catch (err) { console.error(err);