Skip to content

Commit

Permalink
feat(macos): add macOS support for config plugins (#2160)
Browse files Browse the repository at this point in the history
  • Loading branch information
tido64 authored Aug 1, 2024
1 parent 04090d7 commit 4b9227d
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 50 deletions.
4 changes: 2 additions & 2 deletions example/macos/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ PODS:
- React-jsi (= 0.73.33)
- React-logger (= 0.73.33)
- React-perflogger (= 0.73.33)
- ReactNativeHost (0.4.10):
- ReactNativeHost (0.4.11):
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
Expand Down Expand Up @@ -1252,7 +1252,7 @@ SPEC CHECKSUMS:
React-runtimescheduler: 68e2b8754cceaaa8b443d62018d4c9c0aa4e0741
React-utils: 46cc84b17edde38232668073688b2ed621a3d171
ReactCommon: 0b6b092708b879557708b378a09729fc29900918
ReactNativeHost: b74433b0e21ca2aae4fd5c1c3a49cbd1a7edf7ca
ReactNativeHost: 02d9df701ce3f7b6560f95315df4bab38b660f58
ReactTestApp-DevSupport: c4abadbb90a8a9903400407e9857c2a2ef0343fb
ReactTestApp-Resources: 9d83e280b173ba2ee053b8135730dff60f9ab674
RNWWebStorage: 13da272b965c7233d1c0c167f2306f97722323a1
Expand Down
1 change: 1 addition & 0 deletions plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ function withSceneDelegate(config, action) {
});
}

exports.macos = require("./macos");
exports.withReactNativeHost = withReactNativeHost;
exports.withSceneDelegate = withSceneDelegate;
84 changes: 84 additions & 0 deletions plugins/macos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// @ts-check
const { withMod } = require("@expo/config-plugins");

/**
* @typedef {import("@expo/config-plugins").ExportedConfig} ExportedConfig
* @typedef {import("@expo/config-plugins").ExportedConfigWithProps} ExportedConfigWithProps
* @typedef {import("@expo/config-plugins").Mod} Mod
* @typedef {import("@expo/config-plugins").ModConfig} ModConfig
* @typedef {ExportedConfigWithProps & { macos?: { infoPlist?: Record<string, unknown> }}} ExportedConfigWithPropsMac
*/

const macosPlatform = /** @type {keyof ModConfig} */ ("macos");

/**
* Provides the `ReactNativeHost` file for modification.
* @param {ExportedConfig} config Exported config
* @param {Mod} action Method to run on the mod when the config is compiled
* @returns {ExportedConfig} Modified config
*/
function withReactNativeHost(config, action) {
return withMod(config, {
platform: macosPlatform,
mod: "reactNativeHost",
action,
});
}

/**
* Provides the `AppDelegate` file for modification.
* @see {@link https://github.com/expo/expo/blob/sdk-51/packages/%40expo/config-plugins/src/plugins/ios-plugins.ts#L101}
* @param {ExportedConfig} config Exported config
* @param {Mod} action Method to run on the mod when the config is compiled
* @returns {ExportedConfig} Modified config
*/
function withAppDelegate(config, action) {
return withMod(config, {
platform: macosPlatform,
mod: "appDelegate",
action,
});
}

/**
* Provides the `Info.plist` file for modification.
* @see {@link https://github.com/expo/expo/blob/sdk-51/packages/%40expo/config-plugins/src/plugins/ios-plugins.ts#L116}
* @param {ExportedConfig} config Exported config
* @param {Mod} action Method to run on the mod when the config is compiled
* @returns {ExportedConfig} Modified config
*/
function withInfoPlist(config, action) {
return withMod(config, {
platform: macosPlatform,
mod: "infoPlist",
async action(cfg) {
/** @type {ExportedConfigWithPropsMac} */
const config = await action(cfg);
if (!config.macos) {
config.macos = {};
}
config.macos.infoPlist = config.modResults;
return config;
},
});
}

/**
* Provides the main `.xcodeproj` for modification.
* @see {@link https://github.com/expo/expo/blob/sdk-51/packages/%40expo/config-plugins/src/plugins/ios-plugins.ts#L173}
* @param {ExportedConfig} config Exported config
* @param {Mod} action Method to run on the mod when the config is compiled
* @returns {ExportedConfig} Modified config
*/
function withXcodeProject(config, action) {
return withMod(config, {
platform: macosPlatform,
mod: "xcodeproj",
action,
});
}

exports.withAppDelegate = withAppDelegate;
exports.withInfoPlist = withInfoPlist;
exports.withXcodeProject = withXcodeProject;
exports.withReactNativeHost = withReactNativeHost;
4 changes: 1 addition & 3 deletions plugins/reanimated.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ const {
const { getPackageVersion, toVersionNumber, v } = require("../scripts/helpers");
const { withReactNativeHost } = require("./index");

/**
* @typedef {import("@expo/config-plugins").ExportedConfig} ExportedConfig
*/
/** @typedef {import("@expo/config-plugins").ExportedConfig} ExportedConfig */

const NAME = "react-native-reanimated";

Expand Down
2 changes: 2 additions & 0 deletions scripts/config-plugins/index.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check
import { getAndroidModFileProviders } from "./plugins/withAndroidBaseMods.mjs";
import { getIosModFileProviders } from "./plugins/withIosBaseMods.mjs";
import { getMacOsModFileProviders } from "./plugins/withMacOsBaseMods.mjs";

export { applyConfigPlugins } from "./apply.mjs";
export {
Expand All @@ -12,4 +13,5 @@ export { withInternal } from "./plugins/withInternal.mjs";
export const BaseMods = {
getAndroidModFileProviders,
getIosModFileProviders,
getMacOsModFileProviders,
};
53 changes: 53 additions & 0 deletions scripts/config-plugins/plugins/cocoaBaseMods.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// @ts-check
import { createRequire } from "node:module";
import * as path from "node:path";
import { BaseMods } from "../ExpoConfigPlugins.mjs";
import { makeFilePathModifier, makeNullProvider } from "../provider.mjs";

const require = createRequire(import.meta.url);

/**
* @param {import("../types.js").CustomModProvider} modifyFilePath
* @returns {import("../types.js").IosModFileProviders}
*/
export function createModFileProviders(modifyFilePath) {
const modifyReactNativeHostFilePath = makeFilePathModifier(
path.dirname(require.resolve("@rnx-kit/react-native-host/package.json"))
);

const nullProvider = makeNullProvider();

// https://github.com/expo/expo/blob/sdk-51/packages/%40expo/config-plugins/src/plugins/withIosBaseMods.ts
const expoProviders = BaseMods.getIosModFileProviders();

/** @type {import("../types.js").IosModFileProviders} */
const defaultProviders = {
dangerous: expoProviders.dangerous,
finalized: expoProviders.finalized,
appDelegate: modifyFilePath(
expoProviders.appDelegate,
"ReactTestApp/AppDelegate.swift"
),
expoPlist: nullProvider,
xcodeproj: modifyFilePath(
expoProviders.xcodeproj,
"ReactTestApp.xcodeproj/project.pbxproj"
),
infoPlist: modifyFilePath(expoProviders.infoPlist, "Info.plist"),
entitlements: nullProvider,
podfile: makeNullProvider({
path: "",
language: /** @type {const} */ ("rb"),
contents: "",
}),
podfileProperties: makeNullProvider(),
};

// `@rnx-kit/react-native-host` files
defaultProviders["reactNativeHost"] = modifyReactNativeHostFilePath(
expoProviders.appDelegate,
"cocoa/ReactNativeHost.mm"
);

return defaultProviders;
}
7 changes: 7 additions & 0 deletions scripts/config-plugins/plugins/mod-compiler.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { BaseMods, evalModsAsync } from "../ExpoConfigPlugins.mjs";
import { getAndroidModFileProviders } from "./withAndroidBaseMods.mjs";
import { getIosModFileProviders } from "./withIosBaseMods.mjs";
import { getMacOsModFileProviders } from "./withMacOsBaseMods.mjs";

/** @type {import("@expo/config-plugins").withDefaultBaseMods} */
export const withDefaultBaseMods = (config, props) => {
Expand All @@ -13,6 +14,12 @@ export const withDefaultBaseMods = (config, props) => {
...props,
providers: getAndroidModFileProviders(),
});
config = BaseMods.withGeneratedBaseMods(config, {
...props,
// @ts-expect-error `macos` is not assignable to type `android | ios`
platform: "macos",
providers: getMacOsModFileProviders(),
});
return config;
};

Expand Down
2 changes: 1 addition & 1 deletion scripts/config-plugins/plugins/withAndroidBaseMods.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const modifyFilePath = makeFilePathModifier(
"node_modules/react-native-test-app/android"
);

// https://github.com/expo/expo/blob/93cd0503117d5a25f8b80ed7b30ec5bed3a67c24/packages/@expo/config-plugins/src/plugins/withAndroidBaseMods.ts
// https://github.com/expo/expo/blob/sdk-51/packages/%40expo/config-plugins/src/plugins/withAndroidBaseMods.ts
const expoProviders = BaseMods.getAndroidModFileProviders();

/** @type {typeof expoProviders} */
Expand Down
47 changes: 4 additions & 43 deletions scripts/config-plugins/plugins/withIosBaseMods.mjs
Original file line number Diff line number Diff line change
@@ -1,56 +1,17 @@
// @ts-check
import { createRequire } from "node:module";
import * as path from "node:path";
import { createModFileProviders } from "./cocoaBaseMods.mjs";
import { BaseMods } from "../ExpoConfigPlugins.mjs";
import { makeFilePathModifier, makeNullProvider } from "../provider.mjs";
import { makeFilePathModifier } from "../provider.mjs";

const modifyFilePath = makeFilePathModifier("node_modules/.generated/ios");

const require = createRequire(import.meta.url);
const modifyReactNativeHostFilePath = makeFilePathModifier(
path.dirname(require.resolve("@rnx-kit/react-native-host/package.json"))
);

const nullProvider = makeNullProvider();

// https://github.com/expo/expo/blob/93cd0503117d5a25f8b80ed7b30ec5bed3a67c24/packages/@expo/config-plugins/src/plugins/withIosBaseMods.ts
const expoProviders = BaseMods.getIosModFileProviders();

/** @type {typeof expoProviders & Record<string, unknown>} */
const defaultProviders = {
dangerous: expoProviders.dangerous,
finalized: expoProviders.finalized,
appDelegate: modifyFilePath(
expoProviders.appDelegate,
"ReactTestApp/AppDelegate.swift"
),
expoPlist: nullProvider,
xcodeproj: modifyFilePath(
expoProviders.xcodeproj,
"ReactTestApp.xcodeproj/project.pbxproj"
),
infoPlist: modifyFilePath(expoProviders.infoPlist, "Info.plist"),
entitlements: nullProvider,
podfile: makeNullProvider({
path: "",
language: /** @type {const} */ ("rb"),
contents: "",
}),
podfileProperties: makeNullProvider(),
};
const defaultProviders = createModFileProviders(modifyFilePath);

// `react-native-test-app` files
defaultProviders["sceneDelegate"] = modifyFilePath(
expoProviders.appDelegate,
BaseMods.getIosModFileProviders().appDelegate,
"ReactTestApp/SceneDelegate.swift"
);

// `@rnx-kit/react-native-host` files
defaultProviders["reactNativeHost"] = modifyReactNativeHostFilePath(
expoProviders.appDelegate,
"cocoa/ReactNativeHost.mm"
);

export function getIosModFileProviders() {
return defaultProviders;
}
10 changes: 10 additions & 0 deletions scripts/config-plugins/plugins/withMacOsBaseMods.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @ts-check
import { createModFileProviders } from "./cocoaBaseMods.mjs";
import { makeFilePathModifier } from "../provider.mjs";

const modifyFilePath = makeFilePathModifier("node_modules/.generated/macos");
const defaultProviders = createModFileProviders(modifyFilePath);

export function getMacOsModFileProviders() {
return defaultProviders;
}
8 changes: 7 additions & 1 deletion scripts/config-plugins/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ModPlatform } from "@expo/config-plugins";
import type { BaseMods, ModPlatform } from "@expo/config-plugins";
import type {
BaseModProviderMethods,
ForwardedBaseModOptions,
Expand All @@ -12,6 +12,12 @@ export type CustomModProvider = <
file: string
) => BaseModProviderMethods<ModType, Props>;

export type IosModFileProviders = ReturnType<
typeof BaseMods.getIosModFileProviders
> &
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Record<string, BaseModProviderMethods<any, any>>;

export type ProjectInfo = {
projectRoot: string;
platforms: ModPlatform[];
Expand Down
3 changes: 3 additions & 0 deletions test/pack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ describe("npm pack", () => {
"macos/test_app.rb",
"package.json",
"plugins/index.js",
"plugins/macos.js",
"plugins/reanimated.js",
"react-native.config.js",
"schema.json",
Expand All @@ -184,10 +185,12 @@ describe("npm pack", () => {
"scripts/config-plugins/ExpoConfigPlugins.mjs",
"scripts/config-plugins/apply.mjs",
"scripts/config-plugins/index.mjs",
"scripts/config-plugins/plugins/cocoaBaseMods.mjs",
"scripts/config-plugins/plugins/mod-compiler.mjs",
"scripts/config-plugins/plugins/withAndroidBaseMods.mjs",
"scripts/config-plugins/plugins/withInternal.mjs",
"scripts/config-plugins/plugins/withIosBaseMods.mjs",
"scripts/config-plugins/plugins/withMacOsBaseMods.mjs",
"scripts/config-plugins/provider.mjs",
"scripts/config-plugins/types.ts",
"scripts/configure-projects.js",
Expand Down

0 comments on commit 4b9227d

Please sign in to comment.