Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(babel): support all options in top-level object #25172

Merged
merged 2 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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