You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
7.1 KiB
185 lines
7.1 KiB
const lazyImportsBlacklist = require('./lazy-imports-blacklist');
|
|
|
|
let hasWarnedJsxRename = false;
|
|
|
|
module.exports = function (api, options = {}) {
|
|
const { web = {}, native = {} } = options;
|
|
|
|
const bundler = api.caller(getBundler);
|
|
const isWebpack = bundler === 'webpack';
|
|
let platform = api.caller(getPlatform);
|
|
|
|
// If the `platform` prop is not defined then this must be a custom config that isn't
|
|
// defining a platform in the babel-loader. Currently this may happen with Next.js + Expo web.
|
|
if (!platform && isWebpack) {
|
|
platform = 'web';
|
|
}
|
|
|
|
const platformOptions =
|
|
platform === 'web'
|
|
? {
|
|
// Only disable import/export transform when Webpack is used because
|
|
// Metro does not support tree-shaking.
|
|
disableImportExportTransform: !!isWebpack,
|
|
...web,
|
|
}
|
|
: { disableImportExportTransform: false, ...native };
|
|
|
|
// Note that if `options.lazyImports` is not set (i.e., `null` or `undefined`),
|
|
// `metro-react-native-babel-preset` will handle it.
|
|
const lazyImportsOption = options && options.lazyImports;
|
|
|
|
const extraPlugins = [];
|
|
|
|
if ('useTransformReactJsxExperimental' in platformOptions && !hasWarnedJsxRename) {
|
|
// https://github.com/expo/expo/pull/13945#pullrequestreview-724327024
|
|
hasWarnedJsxRename = true;
|
|
console.warn(
|
|
'Warning: useTransformReactJsxExperimental has been renamed to useTransformReactJSXExperimental (capitalized JSX) in react-native@0.64.0'
|
|
);
|
|
}
|
|
|
|
// Set true to disable `@babel/plugin-transform-react-jsx`
|
|
// we override this logic outside of the metro preset so we can add support for
|
|
// React 17 automatic JSX transformations.
|
|
// If the logic for `useTransformReactJSXExperimental` ever changes in `metro-react-native-babel-preset`
|
|
// then this block should be updated to reflect those changes.
|
|
if (!platformOptions.useTransformReactJSXExperimental) {
|
|
extraPlugins.push([
|
|
require('@babel/plugin-transform-react-jsx'),
|
|
{
|
|
// Defaults to `automatic`, pass in `classic` to disable auto JSX transformations.
|
|
runtime: (options && options.jsxRuntime) || 'automatic',
|
|
...(options &&
|
|
options.jsxRuntime !== 'classic' && {
|
|
importSource: (options && options.jsxImportSource) || 'react',
|
|
}),
|
|
},
|
|
]);
|
|
// Purposefully not adding the deprecated packages:
|
|
// `@babel/plugin-transform-react-jsx-self` and `@babel/plugin-transform-react-jsx-source`
|
|
// back to the preset.
|
|
}
|
|
|
|
return {
|
|
presets: [
|
|
[
|
|
// We use `require` here instead of directly using the package name because we want to
|
|
// specifically use the `metro-react-native-babel-preset` installed by this package (ex:
|
|
// `babel-preset-expo/node_modules/`). This way the preset will not change unintentionally.
|
|
// Reference: https://github.com/expo/expo/pull/4685#discussion_r307143920
|
|
require('metro-react-native-babel-preset'),
|
|
{
|
|
// Defaults to undefined, set to something truthy to disable `@babel/plugin-transform-react-jsx-self` and `@babel/plugin-transform-react-jsx-source`.
|
|
withDevTools: platformOptions.withDevTools,
|
|
// Defaults to undefined, set to `true` to disable `@babel/plugin-transform-flow-strip-types`
|
|
disableFlowStripTypesTransform: platformOptions.disableFlowStripTypesTransform,
|
|
// Defaults to undefined, set to `false` to disable `@babel/plugin-transform-runtime`
|
|
enableBabelRuntime: platformOptions.enableBabelRuntime,
|
|
// Defaults to `'default'`, can also use `'hermes-canary'`
|
|
unstable_transformProfile: platformOptions.unstable_transformProfile,
|
|
// Set true to disable `@babel/plugin-transform-react-jsx` and
|
|
// the deprecated packages `@babel/plugin-transform-react-jsx-self`, and `@babel/plugin-transform-react-jsx-source`.
|
|
//
|
|
// Otherwise, you'll sometime get errors like the following (starting in Expo SDK 43, React Native 64, React 17):
|
|
//
|
|
// TransformError App.js: /path/to/App.js: Duplicate __self prop found. You are most likely using the deprecated transform-react-jsx-self Babel plugin.
|
|
// Both __source and __self are automatically set when using the automatic jsxRuntime. Please remove transform-react-jsx-source and transform-react-jsx-self from your Babel config.
|
|
useTransformReactJSXExperimental: true,
|
|
|
|
disableImportExportTransform: platformOptions.disableImportExportTransform,
|
|
lazyImportExportTransform:
|
|
lazyImportsOption === true
|
|
? (importModuleSpecifier) => {
|
|
// Do not lazy-initialize packages that are local imports (similar to `lazy: true`
|
|
// behavior) or are in the blacklist.
|
|
return !(
|
|
importModuleSpecifier.includes('./') ||
|
|
lazyImportsBlacklist.has(importModuleSpecifier)
|
|
);
|
|
}
|
|
: // Pass the option directly to `metro-react-native-babel-preset`, which in turn
|
|
// passes it to `babel-plugin-transform-modules-commonjs`
|
|
lazyImportsOption,
|
|
},
|
|
],
|
|
],
|
|
plugins: [
|
|
getObjectRestSpreadPlugin(),
|
|
...extraPlugins,
|
|
getAliasPlugin(),
|
|
[require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }],
|
|
platform === 'web' && [require.resolve('babel-plugin-react-native-web')],
|
|
isWebpack && platform !== 'web' && [require.resolve('./plugins/disable-ambiguous-requires')],
|
|
].filter(Boolean),
|
|
};
|
|
};
|
|
|
|
function getAliasPlugin() {
|
|
const aliases = {};
|
|
|
|
if (hasModule('@expo/vector-icons')) {
|
|
aliases['react-native-vector-icons'] = '@expo/vector-icons';
|
|
}
|
|
|
|
if (Object.keys(aliases).length) {
|
|
return [
|
|
require.resolve('babel-plugin-module-resolver'),
|
|
{
|
|
alias: aliases,
|
|
},
|
|
];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* metro-react-native-babel-preset configures this plugin with `{ loose: true }`, which breaks all
|
|
* getters and setters in spread objects. We need to add this plugin ourself without that option.
|
|
* @see https://github.com/expo/expo/pull/11960#issuecomment-887796455
|
|
*/
|
|
function getObjectRestSpreadPlugin() {
|
|
return [require.resolve('@babel/plugin-proposal-object-rest-spread'), { loose: false }];
|
|
}
|
|
|
|
function hasModule(name) {
|
|
try {
|
|
return !!require.resolve(name);
|
|
} catch (error) {
|
|
if (error.code === 'MODULE_NOT_FOUND' && error.message.includes(name)) {
|
|
return false;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function getPlatform(caller) {
|
|
return caller && caller.platform;
|
|
}
|
|
|
|
/**
|
|
* Get the name of the `bundler`.
|
|
*
|
|
* @param {*} caller
|
|
*/
|
|
function getBundler(caller) {
|
|
if (!caller) return null;
|
|
|
|
const { bundler, name } = caller;
|
|
|
|
if (!bundler) {
|
|
if (name === 'metro') {
|
|
// This is a hack to determine if metro is being used.
|
|
return 'metro';
|
|
} else if (name === 'next-babel-turbo-loader') {
|
|
// NextJS 11
|
|
return 'webpack';
|
|
} else if (name === 'babel-loader') {
|
|
// expo/webpack-config, gatsby, storybook, and next.js <10
|
|
return 'webpack';
|
|
}
|
|
}
|
|
// Perhaps we should add a check to log once when an unexpected bundler is being used.
|
|
return bundler || null;
|
|
}
|