Skip to content

Commit

Permalink
feat(babel): support all options in top-level object (#25172)
Browse files Browse the repository at this point in the history
# Why

Based on feedback from @gaearon, we now normalize the babel options so
you can use any value in the top-level object, and provide
platform-specific overrides in the sub-objects `web` and `native`.

This PR also adds better documentation for the available options.

# Test Plan

Tests will continue to pass.

---------

Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com>
  • Loading branch information
EvanBacon and expo-bot committed Nov 1, 2023
1 parent 7ed60a2 commit 22c3cf2
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 52 deletions.
1 change: 1 addition & 0 deletions packages/babel-preset-expo/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

### 🎉 New features

- Support all options in top-level object and in `native` and `web` sub-objects. ([#25172](https://github.com/expo/expo/pull/25172) by [@EvanBacon](https://github.com/EvanBacon))
- Use the standard `@babel/preset-react` for all React transformations. ([#25125](https://github.com/expo/expo/pull/25125) by [@EvanBacon](https://github.com/EvanBacon))

### 🐛 Bug fixes
Expand Down
39 changes: 36 additions & 3 deletions packages/babel-preset-expo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ If the `bundler` is not defined, it will default to checking if a `babel-loader`
];
```

This property is passed down to [`@babel/plugin-transform-react-jsx`](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx). This flag does nothing when `native.useTransformReactJSXExperimental` is set to `true` because `@babel/plugin-transform-react-jsx` is omitted.
This property is passed down to [`@babel/plugin-transform-react-jsx`](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx). This flag does nothing when `useTransformReactJSXExperimental` is set to `true` because `@babel/plugin-transform-react-jsx` is omitted.

### [`jsxImportSource`](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx#importsource)

Expand Down Expand Up @@ -115,7 +115,7 @@ The value of `lazyImports` has a few possible effects:
],
```

### `web.disableImportExportTransform`
### `disableImportExportTransform`

Enabling this option will allow your project to run with older JavaScript syntax (i.e. `module.exports`). This option will break tree shaking and increase your bundle size, but will eliminate the following error when `module.exports` is used:

Expand All @@ -127,7 +127,40 @@ Enabling this option will allow your project to run with older JavaScript syntax
[
'babel-preset-expo',
{
web: { disableImportExportTransform: true }
disableImportExportTransform: true
}
],
```

### `unstable_transformProfile`

Changes the engine preset in `metro-react-native-babel-preset` based on the JavaScript engine that is being targeted. In Expo SDK 50 and greater, this is automatically set based on the [`jsEngine`](https://docs.expo.dev/versions/latest/config/app/#jsengine) option in your `app.json`.

### `enableBabelRuntime`

Passed to `metro-react-native-babel-preset`.

### `disableFlowStripTypesTransform`

Passed to `metro-react-native-babel-preset`.

## Platform-specific options

All options can be passed in the platform-specific objects `native` and `web` to provide different settings on different platforms. For example, if you'd like to only apply `disableImportExportTransform` on web, use the following:

```js
[
'babel-preset-expo',
{
// Default value:
disableImportExportTransform: false,

web: {
// Web-specific value:
disableImportExportTransform: true,
},
},
];
```

Platform-specific options have higher priority over top-level options.
15 changes: 10 additions & 5 deletions packages/babel-preset-expo/build/index.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 24 additions & 17 deletions packages/babel-preset-expo/build/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 46 additions & 27 deletions packages/babel-preset-expo/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@ import { expoRouterBabelPlugin } from './expo-router-plugin';
import { lazyImports } from './lazyImports';

type BabelPresetExpoPlatformOptions = {
/** Enable or disable adding the Reanimated plugin by default. @default `true` */
reanimated?: boolean;
/** @deprecated Set `jsxRuntime: 'classic'` to disable automatic JSX handling. */
useTransformReactJSXExperimental?: boolean;
/** Change the policy for handling JSX in a file. Passed to `plugin-transform-react-jsx`. @default `'automatic'` */
jsxRuntime?: 'classic' | 'automatic';
/** Change the source module ID to use when importing an automatic JSX import. Only applied when `jsxRuntime` is `'automatic'` (default). Passed to `plugin-transform-react-jsx`. @default `'react'` */
jsxImportSource?: string;

lazyImports?: boolean;

disableImportExportTransform?: boolean;

// Defaults to undefined, set to `true` to disable `@babel/plugin-transform-flow-strip-types`
disableFlowStripTypesTransform?: boolean;
// Defaults to undefined, set to `false` to disable `@babel/plugin-transform-runtime`
Expand All @@ -17,18 +27,26 @@ type BabelPresetExpoPlatformOptions = {
unstable_transformProfile?: 'default' | 'hermes-stable' | 'hermes-canary';
};

export type BabelPresetExpoOptions = {
lazyImports?: boolean;
reanimated?: boolean;
jsxRuntime?: 'classic' | 'automatic';
jsxImportSource?: string;
export type BabelPresetExpoOptions = BabelPresetExpoPlatformOptions & {
/** Web-specific settings. */
web?: BabelPresetExpoPlatformOptions;
/** Native-specific settings. */
native?: BabelPresetExpoPlatformOptions;
};

function babelPresetExpo(api: ConfigAPI, options: BabelPresetExpoOptions = {}): TransformOptions {
const { web = {}, native = {}, reanimated } = options;
function getOptions(
options: BabelPresetExpoOptions,
platform?: string
): BabelPresetExpoPlatformOptions {
const tag = platform === 'web' ? 'web' : 'native';

return {
...options,
...options[tag],
};
}

function babelPresetExpo(api: ConfigAPI, options: BabelPresetExpoOptions = {}): TransformOptions {
const bundler = api.caller(getBundler);
const isWebpack = bundler === 'webpack';
let platform = api.caller((caller) => (caller as any)?.platform);
Expand All @@ -41,24 +59,25 @@ function babelPresetExpo(api: ConfigAPI, options: BabelPresetExpoOptions = {}):
platform = 'web';
}

const platformOptions: BabelPresetExpoPlatformOptions =
platform === 'web'
? {
// Only disable import/export transform when Webpack is used because
// Metro does not support tree-shaking.
disableImportExportTransform: isWebpack,
unstable_transformProfile: engine === 'hermes' ? 'hermes-stable' : 'default',
...web,
}
: {
disableImportExportTransform: false,
unstable_transformProfile: engine === 'hermes' ? 'hermes-stable' : 'default',
...native,
};
const platformOptions = getOptions(options, platform);

if (platformOptions.disableImportExportTransform == null) {
if (platform === 'web') {
// Only disable import/export transform when Webpack is used because
// Metro does not support tree-shaking.
platformOptions.disableImportExportTransform = isWebpack;
} else {
platformOptions.disableImportExportTransform = false;
}
}

if (platformOptions.unstable_transformProfile == null) {
platformOptions.unstable_transformProfile = engine === 'hermes' ? 'hermes-stable' : 'default';
}

// Note that if `options.lazyImports` is not set (i.e., `null` or `undefined`),
// `metro-react-native-babel-preset` will handle it.
const lazyImportsOption = options?.lazyImports;
const lazyImportsOption = platformOptions?.lazyImports;

const extraPlugins: PluginItem[] = [];

Expand Down Expand Up @@ -150,10 +169,10 @@ function babelPresetExpo(api: ConfigAPI, options: BabelPresetExpoOptions = {}):
development: isDev,

// Defaults to `automatic`, pass in `classic` to disable auto JSX transformations.
runtime: options?.jsxRuntime || 'automatic',
...(options &&
options.jsxRuntime !== 'classic' && {
importSource: (options && options.jsxImportSource) || 'react',
runtime: platformOptions?.jsxRuntime || 'automatic',
...(platformOptions &&
platformOptions.jsxRuntime !== 'classic' && {
importSource: (platformOptions && platformOptions.jsxImportSource) || 'react',
}),

// NOTE: Unexposed props:
Expand All @@ -176,7 +195,7 @@ function babelPresetExpo(api: ConfigAPI, options: BabelPresetExpoOptions = {}):
// Automatically add `react-native-reanimated/plugin` when the package is installed.
// TODO: Move to be a customTransformOption.
hasModule('react-native-reanimated') &&
reanimated !== false && [require.resolve('react-native-reanimated/plugin')],
platformOptions.reanimated !== false && [require.resolve('react-native-reanimated/plugin')],
].filter(Boolean) as PluginItem[],
};
}
Expand Down

0 comments on commit 22c3cf2

Please sign in to comment.