Skip to content

Fix: @bacons/apple-targets compatibility with Expo SDK 54 #144

@adebayoadebisi

Description

@adebayoadebisi

Fixing @bacons/apple-targets for Expo SDK 54

Problem

When upgrading from Expo SDK 52 to SDK 54, the @bacons/apple-targets plugin (v3.0.5) breaks during expo prebuild with the following error:

TypeError: config_plugins_1.BaseMods.provider is not a function

This happens because Expo SDK 54 introduced breaking API changes in @expo/config-plugins that moved certain functions from being properties of BaseMods to standalone exports.

TL;DR

Quick fix for @bacons/apple-targets + Expo SDK 54:

  1. Install: npm install --save-dev patch-package --legacy-peer-deps
  2. Add to package.json: "postinstall": "patch-package"
  3. Edit node_modules/@bacons/apple-targets/build/withXcparse.js (see detailed steps below)
  4. Run: npx patch-package @bacons/apple-targets
  5. Test: npx expo prebuild --clean --platform ios

Full details below ⬇️

Root Cause

In Expo SDK 54's @expo/config-plugins v54.0.2, two critical API changes were made:

  1. BaseMods.provider → Now exported as standalone provider from createBaseMod module
  2. BaseMods.withGeneratedBaseMods → Now exported as standalone withGeneratedBaseMods from createBaseMod module

The @bacons/apple-targets plugin (as of v3.0.5) still uses the old SDK 52/53 API, calling:

  • config_plugins_1.BaseMods.provider({...})
  • config_plugins_1.BaseMods.withGeneratedBaseMods(config, {...})

These function calls fail because they no longer exist on the BaseMods object.

Prerequisites

Before applying this fix, ensure:

  • You're upgrading to or using Expo SDK 54
  • You have @bacons/apple-targets v3.0.5 installed
  • You're using iOS widgets/app extensions
  • You've encountered the BaseMods.provider is not a function error

If you don't have these, this fix may not apply to your situation.

Solution: patch-package

Since there's no official SDK 54-compatible version of @bacons/apple-targets yet, we use patch-package to fix the plugin locally. This approach:

✅ Persists across npm install runs
✅ Works with Expo's Continuous Native Generation (CNG)
✅ Doesn't require forking the plugin
✅ Can be easily removed once official fix is released

Step-by-Step Fix

1. Install patch-package

npm install --save-dev patch-package --legacy-peer-deps

Note: Use --legacy-peer-deps if you encounter React version conflicts (SDK 54 uses React 19).

2. Add postinstall script

Edit your package.json to add the postinstall hook:

{
  "scripts": {
    "postinstall": "patch-package"
  }
}

3. Apply the fix to node_modules

Edit node_modules/@bacons/apple-targets/build/withXcparse.js:

Add this import after the existing imports (around line 30):

const createBaseMod_1 = require("@expo/config-plugins/build/plugins/createBaseMod");

Find and replace (around line 42):

// BEFORE: ❌
return config_plugins_1.BaseMods.withGeneratedBaseMods(config, {

// AFTER: ✅
return (0, createBaseMod_1.withGeneratedBaseMods)(config, {

Find and replace (around line 47):

// BEFORE: ❌
[customModName]: config_plugins_1.BaseMods.provider({

// AFTER: ✅
[customModName]: (0, createBaseMod_1.provider)({

4. Generate the patch file

npx patch-package @bacons/apple-targets

This creates patches/@bacons+apple-targets+3.0.5.patch in your project root.

5. Test the fix

npx expo prebuild --clean --platform ios

The prebuild should now succeed without errors.

Success looks like:

✔ Created native directories | iOS, Android
✔ Updated Info.plist
✔ Updated Podfile
✔ Installing CocoaPods dependencies
✔ Your widget targets appear in the Xcode project

If you see these, the patch worked! 🎉

The Patch File

The complete patch file (patches/@bacons+apple-targets+3.0.5.patch) looks like this:

diff --git a/node_modules/@bacons/apple-targets/build/withXcparse.js b/node_modules/@bacons/apple-targets/build/withXcparse.js
index 36e2ccb..000a537 100644
--- a/node_modules/@bacons/apple-targets/build/withXcparse.js
+++ b/node_modules/@bacons/apple-targets/build/withXcparse.js
@@ -27,6 +27,7 @@ exports.withXcodeProjectBetaBaseMod = exports.withXcodeProjectBeta = void 0;
 const xcode_1 = require("@bacons/xcode");
 const xcodeParse = __importStar(require("@bacons/xcode/json"));
 const config_plugins_1 = require("@expo/config-plugins");
+const createBaseMod_1 = require("@expo/config-plugins/build/plugins/createBaseMod");
 const fs = __importStar(require("fs"));
 const customModName = "xcodeProjectBeta2";
 const withXcodeProjectBeta = (config, action) => {
@@ -38,13 +39,13 @@ const withXcodeProjectBeta = (config, action) => {
 };
 exports.withXcodeProjectBeta = withXcodeProjectBeta;
 const withXcodeProjectBetaBaseModInternal = (config) => {
-    return config_plugins_1.BaseMods.withGeneratedBaseMods(config, {
+    return (0, createBaseMod_1.withGeneratedBaseMods)(config, {
         platform: "ios",
         saveToInternal: true,
         skipEmptyMod: false,
         providers: {
             // Append a custom rule to supply AppDelegate header data to mods on `mods.ios.AppClipInfoPlist`
-            [customModName]: config_plugins_1.BaseMods.provider({
+            [customModName]: (0, createBaseMod_1.provider)({
                 isIntrospective: false,
                 // isIntrospective: true,
                 async getFilePath({ modRequest, _internal }) {

Verification

After applying the patch, you should see:

  1. expo prebuild completes without errors
  2. ✅ iOS project includes your widget extension targets
  3. ✅ CocoaPods installation succeeds
  4. ✅ iOS build compiles successfully

Tested Scenarios

This fix has been verified to work with:

  • ✅ iOS widgets (multiple widget types + Live Activities)
  • ✅ Expo development builds
  • ✅ Multiple widget targets in a single project
  • ✅ CocoaPods installation
  • ✅ Production iOS builds

Note: This patch specifically addresses the prebuild phase. If you encounter runtime widget issues, those are separate from this fix.

Troubleshooting

Patch doesn't apply

  • Error: patch-package: ERROR: Failed to apply patch
  • Solution: Delete node_modules and reinstall, then try again
  • Check: Ensure you have @bacons/apple-targets version 3.0.5 exactly

Still getting "provider is not a function"

  • Check 1: Verify patch file exists: patches/@bacons+apple-targets+3.0.5.patch
  • Check 2: Confirm postinstall script ran: npm run postinstall manually
  • Check 3: Clear Metro cache: npx expo start -c
  • Check 4: Delete node_modules and ios folder, reinstall everything

Different version of @bacons/apple-targets

  • This patch is for v3.0.5 specifically
  • For other versions, the line numbers may differ
  • Check the actual file and adjust the patch accordingly
  • You may need to create your own patch following the same pattern

Prebuild succeeds but widgets don't show up

  • This fix only addresses the prebuild error
  • Widget runtime issues are separate - check your widget code and entitlements
  • Ensure your App Group is correctly configured

Why This Happens

Expo SDK 54 represents a major upgrade that includes:

  • React Native 0.81.4
  • React 19.1.0
  • Significant internal API refactoring in @expo/config-plugins

The @expo/config-plugins team moved some internal APIs to improve modularity. While this is good for long-term maintainability, it breaks plugins that relied on the old API structure.

Alternative Approaches Considered

1. Manual Xcode Integration

Rejected because Expo's Continuous Native Generation (CNG) wipes out manual changes on every expo prebuild --clean.

2. Wait for Official Fix

Rejected because users already rely on widgets. There's no timeline for an official SDK 54-compatible release.

3. Fork and Maintain Plugin

Considered but patch-package is simpler and easier to remove once the official fix arrives.

4. Downgrade to SDK 53

Rejected because it would lose all SDK 54 upgrade work and delay access to new features.

When to Remove This Patch

Remove the patch when:

  1. @bacons/apple-targets releases an SDK 54-compatible version, OR
  2. You migrate to a different widget solution, OR
  3. Expo provides native widget support

To remove:

rm patches/@bacons+apple-targets+3.0.5.patch
npm install @bacons/apple-targets@latest

Related Issues

Contributing Back

If this fix helps you, consider:

  1. Testing it thoroughly with your widget implementation
  2. Reporting your success/issues on the @bacons/apple-targets repo
  3. Offering to submit a PR with this fix
  4. Sharing your experience to help others encountering the same issue

Credits

This fix was discovered and tested by Adebayo Adebisi (@adebayoadebisi) during a production app upgrade from Expo SDK 52 to SDK 54, where maintaining iOS widget functionality was critical for existing users.

Special thanks to the Expo and @bacons/apple-targets communities for their excellent tooling.


Last Updated: October 2025
Tested With:

  • Expo SDK 54.0.13
  • @bacons/apple-targets 3.0.5
  • @expo/config-plugins 54.0.2
  • React Native 0.81.4
  • React 19.1.0
  • Xcode 26.0.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions