fix(android): with-release-signing plugin requires '@expo/config-plugins' from non-declared dep — use 'expo/config-plugins' re-export #284

Closed
opened 2026-06-24 14:01:35 +00:00 by james · 0 comments
Owner

Symptom

release-android.yml (run #708) now reaches Gradle task execution (thanks #279) but fails at:

> Task :expo-constants:createExpoConfig FAILED
> Task :app:createBundleReleaseJsAndAssets FAILED

Error: Cannot find module '@expo/config-plugins'
Require stack:
- /workspace/.../apps/client/plugins/with-release-signing.js

Root cause

apps/client/plugins/with-release-signing.js line 32 does:

const { withAppBuildGradle } = require("@expo/config-plugins");

but @expo/config-plugins is not declared in apps/client/package.json — neither as a direct dep nor a peer. The Gradle tasks :expo-constants:createExpoConfig and :app:createBundleReleaseJsAndAssets spawn node processes that resolve the plugin from the strict pnpm node_modules layout, where unscoped transitives aren't visible.

This bug has been latent since #187 added the plugin. The previous release-android runs never surfaced it because they died earlier — at the foojay/IBM_SEMERU configuration-phase blowup that #279 fixed.

Fix

Official Expo plugins use require("expo/config-plugins") — a one-line re-export from the expo package (expo/config-plugins.js is literally module.exports = require('@expo/config-plugins')). That works without a separate dep declaration because expo is already a direct dep of @carol/client.

Change apps/client/plugins/with-release-signing.js line 32:

// before
const { withAppBuildGradle } = require("@expo/config-plugins");
// after
const { withAppBuildGradle } = require("expo/config-plugins");

Matches the pattern used by every other Expo config plugin in the ecosystem (expo-secure-store/plugin/build/withSecureStore.js, etc.).

Acceptance

The next release-android run gets past :expo-constants:createExpoConfig and :app:createBundleReleaseJsAndAssets. The plugin's runtime behaviour is unchanged — it's the same module either way.

Out of scope

The in-tree vitest test for the plugin (covered in #187) imports the module via a different path — confirm it still passes after the require swap, but no test changes expected.

## Symptom `release-android.yml` (run [#708](https://forge.wynning.tech/james/carol/actions/runs/708)) now reaches Gradle task execution (thanks #279) but fails at: ``` > Task :expo-constants:createExpoConfig FAILED > Task :app:createBundleReleaseJsAndAssets FAILED Error: Cannot find module '@expo/config-plugins' Require stack: - /workspace/.../apps/client/plugins/with-release-signing.js ``` ## Root cause `apps/client/plugins/with-release-signing.js` line 32 does: ```js const { withAppBuildGradle } = require("@expo/config-plugins"); ``` but `@expo/config-plugins` is **not declared** in `apps/client/package.json` — neither as a direct dep nor a peer. The Gradle tasks `:expo-constants:createExpoConfig` and `:app:createBundleReleaseJsAndAssets` spawn `node` processes that resolve the plugin from the strict pnpm node_modules layout, where unscoped transitives aren't visible. This bug has been latent since #187 added the plugin. The previous release-android runs never surfaced it because they died earlier — at the foojay/IBM_SEMERU configuration-phase blowup that #279 fixed. ## Fix Official Expo plugins use `require("expo/config-plugins")` — a one-line re-export from the `expo` package (`expo/config-plugins.js` is literally `module.exports = require('@expo/config-plugins')`). That works without a separate dep declaration because `expo` is already a direct dep of `@carol/client`. Change `apps/client/plugins/with-release-signing.js` line 32: ```js // before const { withAppBuildGradle } = require("@expo/config-plugins"); // after const { withAppBuildGradle } = require("expo/config-plugins"); ``` Matches the pattern used by every other Expo config plugin in the ecosystem (`expo-secure-store/plugin/build/withSecureStore.js`, etc.). ## Acceptance The next release-android run gets past `:expo-constants:createExpoConfig` and `:app:createBundleReleaseJsAndAssets`. The plugin's runtime behaviour is unchanged — it's the same module either way. ## Out of scope The in-tree vitest test for the plugin (covered in #187) imports the module via a different path — confirm it still passes after the require swap, but no test changes expected.
james closed this issue 2026-06-24 16:26:03 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
james/carol#284
No description provided.