From d8128d711ae8054fcc2e8476efc77fe9838be98c Mon Sep 17 00:00:00 2001 From: Tommy Nguyen <4123478+tido64@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:21:26 +0200 Subject: [PATCH] fix(macos): add Xcode project configuration This is currently unused by `react-native-macos` but will be used in the future: https://github.com/microsoft/react-native-macos/pull/2995 --- packages/app/example/react-native.config.js | 3 +++ packages/app/macos/template.config.mjs | 17 ++++++++++++----- packages/app/scripts/types.ts | 5 +++++ .../configure/gatherConfig.test.mts.snapshot | 10 +++++----- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/app/example/react-native.config.js b/packages/app/example/react-native.config.js index 20420a235..3edf9ae79 100644 --- a/packages/app/example/react-native.config.js +++ b/packages/app/example/react-native.config.js @@ -8,6 +8,9 @@ const project = (() => { ios: { sourceDir: "ios", }, + macos: { + sourceDir: "macos", + }, windows: { sourceDir: "windows", solutionFile: "windows/Example.sln", diff --git a/packages/app/macos/template.config.mjs b/packages/app/macos/template.config.mjs index 813eb32aa..2b86c758a 100644 --- a/packages/app/macos/template.config.mjs +++ b/packages/app/macos/template.config.mjs @@ -3,15 +3,22 @@ import * as nodefs from "node:fs"; import { podfile } from "../ios/template.config.mjs"; import { toVersionNumber } from "../scripts/helpers.js"; -/** @import { Configuration, ConfigureParams } from "../scripts/types.js"; */ +/** + * @import { + * Configuration, + * ConfigureParams, + * ProjectConfig, + * ProjectParams, + * } from "../scripts/types.js"; + */ /** * @param {string} _projectRoot - * @param {unknown} _config - * @returns {undefined} + * @param {Required["macos"]} config + * @returns {ProjectParams["macos"] | undefined} */ -export function configure(_projectRoot, _config, _fs = nodefs) { - return undefined; +export function configure(_projectRoot, config, _fs = nodefs) { + return config; } /** diff --git a/packages/app/scripts/types.ts b/packages/app/scripts/types.ts index eb62f787f..76eeac3f3 100644 --- a/packages/app/scripts/types.ts +++ b/packages/app/scripts/types.ts @@ -133,6 +133,10 @@ export type ProjectParams = { sourceDir?: string; project?: string; }; + macos: { + sourceDir?: string; + project?: string; + }; windows: { sourceDir: string; solutionFile: string; @@ -147,6 +151,7 @@ export type ProjectParams = { export type ProjectConfig = { android?: Pick; ios?: Pick; + macos?: Pick; windows?: Pick; [platform: string]: unknown; }; diff --git a/packages/app/test/configure/gatherConfig.test.mts.snapshot b/packages/app/test/configure/gatherConfig.test.mts.snapshot index c3e6a44a7..19e6db8f5 100644 --- a/packages/app/test/configure/gatherConfig.test.mts.snapshot +++ b/packages/app/test/configure/gatherConfig.test.mts.snapshot @@ -13,7 +13,7 @@ exports[`gatherConfig() > returns common configuration 1`] = ` "metro.config.js": { "source": "example/metro.config.js" }, - "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", + "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n macos: {\\n sourceDir: \\"macos\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", "common/.gitignore": { "source": "example/.gitignore" }, @@ -26,7 +26,7 @@ exports[`gatherConfig() > returns common configuration 1`] = ` "common/metro.config.js": { "source": "example/metro.config.js" }, - "common/react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n" + "common/react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n macos: {\\n sourceDir: \\"macos\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n" }, "oldFiles": [], "scripts": { @@ -51,7 +51,7 @@ exports[`gatherConfig() > returns configuration for a single platform 1`] = ` "metro.config.js": { "source": "example/metro.config.js" }, - "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", + "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n macos: {\\n sourceDir: \\"macos\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", "ios/Podfile": "ws_dir = Pathname.new(__dir__)\\nws_dir = ws_dir.parent until\\n File.exist?(\\"#{ws_dir}/node_modules/react-native-test-app/test_app.rb\\") ||\\n ws_dir.expand_path.to_s == '/'\\nrequire \\"#{ws_dir}/node_modules/react-native-test-app/test_app.rb\\"\\n\\nworkspace 'Test.xcworkspace'\\n\\nuse_test_app! :hermes_enabled => true, :fabric_enabled => true\\n" }, "oldFiles": [ @@ -84,7 +84,7 @@ exports[`gatherConfig() > returns configuration for all platforms 1`] = ` "metro.config.js": { "source": "example/metro.config.js" }, - "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", + "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n macos: {\\n sourceDir: \\"macos\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", "android/build.gradle": "buildscript {\\n apply(from: {\\n def searchDir = rootDir.toPath()\\n do {\\n def p = searchDir.resolve(\\"node_modules/react-native-test-app/android/dependencies.gradle\\")\\n if (p.toFile().exists()) {\\n return p.toRealPath().toString()\\n }\\n } while (searchDir = searchDir.getParent())\\n throw new GradleException(\\"Could not find \`react-native-test-app\`\\");\\n }())\\n\\n repositories {\\n mavenCentral()\\n google()\\n }\\n\\n dependencies {\\n getReactNativeDependencies().each { dependency ->\\n classpath(dependency)\\n }\\n }\\n}\\n", "android/gradle/wrapper/gradle-wrapper.jar": { "source": "example/android/gradle/wrapper/gradle-wrapper.jar" @@ -152,7 +152,7 @@ exports[`gatherConfig() > returns configuration for arbitrary platforms 1`] = ` "metro.config.js": { "source": "example/metro.config.js" }, - "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", + "react-native.config.js": "const project = (() => {\\n try {\\n const { configureProjects } = require(\\"react-native-test-app\\");\\n return configureProjects({\\n android: {\\n sourceDir: \\"android\\",\\n },\\n ios: {\\n sourceDir: \\"ios\\",\\n },\\n macos: {\\n sourceDir: \\"macos\\",\\n },\\n windows: {\\n sourceDir: \\"windows\\",\\n solutionFile: \\"windows/Test.sln\\",\\n },\\n });\\n } catch (_) {\\n return undefined;\\n }\\n})();\\n\\nmodule.exports = {\\n ...(project ? { project } : undefined),\\n};\\n", "android/build.gradle": "buildscript {\\n apply(from: {\\n def searchDir = rootDir.toPath()\\n do {\\n def p = searchDir.resolve(\\"node_modules/react-native-test-app/android/dependencies.gradle\\")\\n if (p.toFile().exists()) {\\n return p.toRealPath().toString()\\n }\\n } while (searchDir = searchDir.getParent())\\n throw new GradleException(\\"Could not find \`react-native-test-app\`\\");\\n }())\\n\\n repositories {\\n mavenCentral()\\n google()\\n }\\n\\n dependencies {\\n getReactNativeDependencies().each { dependency ->\\n classpath(dependency)\\n }\\n }\\n}\\n", "android/gradle/wrapper/gradle-wrapper.jar": { "source": "example/android/gradle/wrapper/gradle-wrapper.jar"