Skip to content

Add precompiled iOS dependency preparation support#3556

Merged
sjchmiela merged 3 commits intomainfrom
stanley/add-precompiled-deps-support
Mar 30, 2026
Merged

Add precompiled iOS dependency preparation support#3556
sjchmiela merged 3 commits intomainfrom
stanley/add-precompiled-deps-support

Conversation

@sjchmiela
Copy link
Copy Markdown
Contributor

@sjchmiela sjchmiela commented Mar 27, 2026

Summary

  • export precompiled modules helpers from @expo/build-tools and start preparation when flagged builds enable precompiled modules
  • wait for precompiled module preparation before running pod install in both build-tools pod flows
  • set worker env and config for precompiled module downloads, including proxy-aware download handling and coverage for the new behavior

Testing

Zrzut ekranu 2026-03-28 o 22 26 35 Zrzut ekranu 2026-03-28 o 22 27 27

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 27, 2026

Codecov Report

❌ Patch coverage is 92.77108% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.92%. Comparing base (7a4c81f) to head (77ef2ed).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...ckages/build-tools/src/utils/precompiledModules.ts 91.55% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3556      +/-   ##
==========================================
+ Coverage   53.80%   53.92%   +0.13%     
==========================================
  Files         820      822       +2     
  Lines       34978    35076      +98     
  Branches     7217     7229      +12     
==========================================
+ Hits        18815    18911      +96     
- Misses      16072    16078       +6     
+ Partials       91       87       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sjchmiela sjchmiela added the no changelog PR that doesn't require a changelog entry label Mar 28, 2026
@github-actions
Copy link
Copy Markdown

⏩ The changelog entry check has been skipped since the "no changelog" label is present.

@sjchmiela sjchmiela marked this pull request as ready for review March 28, 2026 21:27
@sjchmiela sjchmiela requested review from chrfalch and hSATAC March 28, 2026 21:27
@github-actions
Copy link
Copy Markdown

Subscribed to pull request

File Patterns Mentions
**/* @douglowder

Generated by CodeMention

@chrfalch
Copy link
Copy Markdown

I’m not yet experienced with the build tools, but I’ve gone through the PR and as far as i can see it looks good. This is also a test for supporting precompiled frameworks on iOS in EAS build so there will definitely be room for some improvements when we get decent packaging and versioning of these modules.

@sjchmiela sjchmiela requested a review from AbbanMustafa March 30, 2026 16:30
precompiledModulesUrls: [
'https://storage.googleapis.com/turtle-v2/precompiled-modules/db65b4afac835ff71269ce53937fb20627b133c0/xcframeworks-Debug.zip',
'https://storage.googleapis.com/turtle-v2/precompiled-modules/db65b4afac835ff71269ce53937fb20627b133c0/xcframeworks-Release.zip',
],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just leaving note that this is for sake of testing and POC. We will later need to ensure we publish and download the proper versions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, from what I heard the plan is to distribute individual xcframeworks inside NPM packages. This solves both distribution and versioning!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for preparing/downloading precompiled iOS dependency archives ahead of CocoaPods installation, wiring the behavior through the worker and build-tools layers.

Changes:

  • Introduces build-tools helpers to download/extract precompiled module archives (with proxy-aware download fallback) and to wait for preparation before pod install.
  • Wires worker startup to optionally kick off precompiled module preparation and sets related iOS env vars when a build is flagged.
  • Adds unit + integration test coverage for preparation, waiting behavior, and pod-install gating.

Reviewed changes

Copilot reviewed 13 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/worker/src/env.ts Sets EXPO_USE_PRECOMPILED_MODULES / EXPO_PRECOMPILED_MODULES_PATH for flagged iOS jobs.
packages/worker/src/config.ts Adds configured URLs for precompiled module archives.
packages/worker/src/build.ts Starts precompiled module preparation at builder spin-up.
packages/worker/src/unit/runtimeEnvironment.test.ts Adjusts test context shaping used by runtime environment preparation tests.
packages/worker/src/unit/env.test.ts Adds test asserting precompiled-module env vars are set for flagged iOS jobs.
packages/build-tools/src/utils/precompiledModules.ts New implementation for downloading/extracting precompiled modules + wait helper.
packages/build-tools/src/utils/tests/precompiledModules.test.ts Unit tests for proxy download/fallback, extraction, cleanup, and timeout waiting.
packages/build-tools/src/utils/integration-tests/precompiledModules.test.ts Integration test verifying merged archive extraction into the expected tree.
packages/build-tools/src/utils/integration-tests/fixtures/precompiledModules/xcframeworks-Release.zip Fixture archive used by integration test.
packages/build-tools/src/utils/integration-tests/fixtures/precompiledModules/xcframeworks-Debug.zip Fixture archive used by integration test.
packages/build-tools/src/steps/functions/installPods.ts Waits for precompiled module preparation before running pod install (steps-based flow).
packages/build-tools/src/steps/functions/tests/installPods.test.ts Tests that pod install waits (and continues on failure).
packages/build-tools/src/ios/pod.ts Waits for precompiled module preparation before running pod install (non-steps iOS flow).
packages/build-tools/src/ios/tests/pod.test.ts Tests that iOS pod install waits (and continues on failure).
packages/build-tools/src/index.ts Exports the new precompiled-module helpers from @expo/build-tools.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +14 to +27
export function shouldUsePrecompiledDependencies(env: Record<string, string | undefined>): boolean {
return env.EAS_USE_PRECOMPILED_MODULES === '1';
}

export function maybeStartPreparingPrecompiledModules(
ctx: BuildContext,
config: { precompiledModulesUrls: string[] }
): void {
if (!shouldUsePrecompiledDependencies(ctx.env)) {
return;
}

startPreparingPrecompiledDependencies(ctx, config.precompiledModulesUrls);
}
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldUsePrecompiledDependencies only checks EAS_USE_PRECOMPILED_MODULES, but in the worker flow the build env that reaches BuildContext.env is set to EXPO_USE_PRECOMPILED_MODULES (see packages/worker/src/env.ts). As a result maybeStartPreparingPrecompiledModules(ctx, config) will never start downloads for flagged jobs because ctx.env.EAS_USE_PRECOMPILED_MODULES is not set. Consider making shouldUsePrecompiledDependencies accept the derived EXPO_USE_PRECOMPILED_MODULES flag as well (or ensure EAS_USE_PRECOMPILED_MODULES is propagated into ctx.env).

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +35
precompiledModulesPreparationPromise = preparePrecompiledDependenciesAsync({
logger: ctx.logger,
urls,
destinationDirectory: PRECOMPILED_MODULES_PATH,
cocoapodsProxyUrl: ctx.env.EAS_BUILD_COCOAPODS_CACHE_URL,
});
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

startPreparingPrecompiledDependencies assigns the async preparation promise to a module-scoped variable without attaching a rejection handler. If the build aborts/fails before a later waitForPrecompiledModulesPreparationAsync() call, a rejection from preparePrecompiledDependenciesAsync can surface as an unhandled promise rejection in the process. Consider always attaching a .catch(...) here to log/record the failure and clear/reset the stored promise (while still allowing callers to await/inspect the result if desired).

Suggested change
precompiledModulesPreparationPromise = preparePrecompiledDependenciesAsync({
logger: ctx.logger,
urls,
destinationDirectory: PRECOMPILED_MODULES_PATH,
cocoapodsProxyUrl: ctx.env.EAS_BUILD_COCOAPODS_CACHE_URL,
});
const promise = preparePrecompiledDependenciesAsync({
logger: ctx.logger,
urls,
destinationDirectory: PRECOMPILED_MODULES_PATH,
cocoapodsProxyUrl: ctx.env.EAS_BUILD_COCOAPODS_CACHE_URL,
}).catch(error => {
ctx.logger.error({ error }, 'Failed to prepare precompiled dependencies');
precompiledModulesPreparationPromise = null;
throw error;
});
precompiledModulesPreparationPromise = promise;

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +57
export async function waitForPrecompiledModulesPreparationAsync(): Promise<void> {
if (!precompiledModulesPreparationPromise) {
return;
}

let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
try {
await Promise.race([
precompiledModulesPreparationPromise,
new Promise<void>((_, reject) => {
timeoutHandle = setTimeout(() => {
reject(
new Error(
`Timed out waiting for precompiled dependencies after ${PRECOMPILED_MODULES_WAIT_TIMEOUT_MS / 1000} seconds`
)
);
}, PRECOMPILED_MODULES_WAIT_TIMEOUT_MS);
timeoutHandle.unref?.();
}),
]);
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waitForPrecompiledModulesPreparationAsync times out after 30s but does not cancel the underlying preparation; callers then proceed (e.g. pod install) while download/extraction may still be mutating PRECOMPILED_MODULES_PATH in the background. This can lead to racy behavior where pods see a partially-prepared tree. Consider either (a) making the timeout configurable and long enough to reliably finish, or (b) adding cancellation (e.g. AbortController) and ensuring the preparation stops/cleans up before continuing.

Copilot uses AI. Check for mistakes.
@sjchmiela sjchmiela merged commit 66d8e3d into main Mar 30, 2026
15 checks passed
@sjchmiela sjchmiela deleted the stanley/add-precompiled-deps-support branch March 30, 2026 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changelog PR that doesn't require a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants