Skip to content

react-native-svg-transformer/expo breaks EXPO_PUBLIC_* env var inlining during expo export (works for expo export:embed) #501

@ingokpp

Description

@ingokpp

Summary

When metro.config.js sets babelTransformerPath to require.resolve('react-native-svg-transformer/expo'), babel-preset-expo's expo-inline-or-reference-env-vars plugin no longer inlines EXPO_PUBLIC_* env vars during npx expo export (the command used by OTA tooling like eas update, eoas publish, etc.). The same transformer config works correctly during npx expo export:embed (the native-build path used by eas build).

Result: OTA bundles ship with process.env.EXPO_PUBLIC_* resolving to undefined at runtime, even though .ipa/.aab built from the same source tree have the values correctly inlined.

Environment

  • react-native-svg-transformer: 1.5.3
  • expo: ^55.0.0 (babel-preset-expo from this SDK)
  • react-native: 0.83.6
  • Workflow: bare (ios/ + android/ checked in)

metro.config.js (relevant lines)

const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
config.transformer = {
  ...config.transformer,
  babelTransformerPath: require.resolve('react-native-svg-transformer/expo'),
};
config.resolver = {
  ...config.resolver,
  assetExts: config.resolver.assetExts.filter((ext) => ext !== 'svg'),
  sourceExts: [...config.resolver.sourceExts, 'svg'],
};
module.exports = config;

Reproduction

EXPO_PUBLIC_API_BASE_URL=https://api.example.com \
NODE_ENV=production \
npx expo export --platform ios --output-dir dist-test

grep -ao "api\.example\.com" dist-test/_expo/static/js/ios/entry-*.hbc | wc -l

Empirical matrix

Comparing babelTransformerPath values, all other things equal:

metro.config.js expo export URL count expo export:embed URL count
react-native-svg-transformer/expo 0 1 ✅
react-native-svg-transformer (root) 1 ✅ 1 ✅
(default — no override) 1 ✅ 1 ✅

Switching from the /expo subpath to the root entry point of the same package fully fixes env var inlining for expo export, while still bundling SVGs correctly.

Hypothesis

babel-preset-expo's expo-inline-or-reference-env-vars plugin reads api.caller(getIsProd) to decide whether to inline process.env.EXPO_PUBLIC_* as literals (production) or replace them with imports from expo/virtual/env (development). I suspect the /expo subpath's createTransformer wrapper doesn't forward the Metro babel caller context (specifically caller.isDev === false) when expo export invokes it, so the plugin falls through to the development branch — which only resolves env values when a dev server is running. expo export:embed apparently invokes Metro with caller context that survives the wrapper, which is why native builds (and store-shipped binaries) are unaffected.

Impact

Anyone using `react-native-svg-transformer/expo` together with self-hosted OTA setups (`expo-open-ota`, custom Updates protocol implementations) — or EAS Update without realizing — will ship JS bundles where `EXPO_PUBLIC_*` is silently `undefined`. The bundle still launches; downstream `fetch`/network/auth code fails at runtime. Hard to diagnose because native builds work fine.

Workaround

Use `require.resolve('react-native-svg-transformer')` (root) instead of `/expo`.

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