128 lines
4.5 KiB
JavaScript
128 lines
4.5 KiB
JavaScript
|
const lazyImportsBlacklist = require('./lazy-imports-blacklist');
|
||
|
|
||
|
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'
|
||
|
? { disableImportExportTransform: true, ...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;
|
||
|
|
||
|
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`
|
||
|
useTransformReactJsxExperimental: platformOptions.useTransformReactJsxExperimental,
|
||
|
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: [
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|