1"use strict"; 2Object.defineProperty(exports, "__esModule", { value: true }); 3const lazyImports_1 = require("./lazyImports"); 4function babelPresetExpo(api, options = {}) { 5 const { web = {}, native = {}, reanimated } = options; 6 const bundler = api.caller(getBundler); 7 const isWebpack = bundler === 'webpack'; 8 let platform = api.caller((caller) => caller?.platform); 9 // If the `platform` prop is not defined then this must be a custom config that isn't 10 // defining a platform in the babel-loader. Currently this may happen with Next.js + Expo web. 11 if (!platform && isWebpack) { 12 platform = 'web'; 13 } 14 const platformOptions = platform === 'web' 15 ? { 16 // Only disable import/export transform when Webpack is used because 17 // Metro does not support tree-shaking. 18 disableImportExportTransform: isWebpack, 19 ...web, 20 } 21 : { disableImportExportTransform: false, ...native }; 22 // Note that if `options.lazyImports` is not set (i.e., `null` or `undefined`), 23 // `metro-react-native-babel-preset` will handle it. 24 const lazyImportsOption = options?.lazyImports; 25 const extraPlugins = [ 26 // `metro-react-native-babel-preset` configures this plugin with `{ loose: true }`, which breaks all 27 // getters and setters in spread objects. We need to add this plugin ourself without that option. 28 // @see https://github.com/expo/expo/pull/11960#issuecomment-887796455 29 [require.resolve('@babel/plugin-proposal-object-rest-spread'), { loose: false }], 30 ]; 31 // Set true to disable `@babel/plugin-transform-react-jsx` 32 // we override this logic outside of the metro preset so we can add support for 33 // React 17 automatic JSX transformations. 34 // If the logic for `useTransformReactJSXExperimental` ever changes in `metro-react-native-babel-preset` 35 // then this block should be updated to reflect those changes. 36 if (!platformOptions.useTransformReactJSXExperimental) { 37 extraPlugins.push([ 38 require('@babel/plugin-transform-react-jsx'), 39 { 40 // Defaults to `automatic`, pass in `classic` to disable auto JSX transformations. 41 runtime: (options && options.jsxRuntime) || 'automatic', 42 ...(options && 43 options.jsxRuntime !== 'classic' && { 44 importSource: (options && options.jsxImportSource) || 'react', 45 }), 46 }, 47 ]); 48 // Purposefully not adding the deprecated packages: 49 // `@babel/plugin-transform-react-jsx-self` and `@babel/plugin-transform-react-jsx-source` 50 // back to the preset. 51 } 52 const aliasPlugin = getAliasPlugin(); 53 if (aliasPlugin) { 54 extraPlugins.push(aliasPlugin); 55 } 56 if (platform === 'web') { 57 extraPlugins.push(require.resolve('babel-plugin-react-native-web')); 58 } 59 return { 60 presets: [ 61 [ 62 // We use `require` here instead of directly using the package name because we want to 63 // specifically use the `metro-react-native-babel-preset` installed by this package (ex: 64 // `babel-preset-expo/node_modules/`). This way the preset will not change unintentionally. 65 // Reference: https://github.com/expo/expo/pull/4685#discussion_r307143920 66 require('metro-react-native-babel-preset'), 67 { 68 // Defaults to undefined, set to something truthy to disable `@babel/plugin-transform-react-jsx-self` and `@babel/plugin-transform-react-jsx-source`. 69 withDevTools: platformOptions.withDevTools, 70 // Defaults to undefined, set to `true` to disable `@babel/plugin-transform-flow-strip-types` 71 disableFlowStripTypesTransform: platformOptions.disableFlowStripTypesTransform, 72 // Defaults to undefined, set to `false` to disable `@babel/plugin-transform-runtime` 73 enableBabelRuntime: platformOptions.enableBabelRuntime, 74 // Defaults to `'default'`, can also use `'hermes-canary'` 75 unstable_transformProfile: platformOptions.unstable_transformProfile, 76 // Set true to disable `@babel/plugin-transform-react-jsx` and 77 // the deprecated packages `@babel/plugin-transform-react-jsx-self`, and `@babel/plugin-transform-react-jsx-source`. 78 // 79 // Otherwise, you'll sometime get errors like the following (starting in Expo SDK 43, React Native 64, React 17): 80 // 81 // TransformError App.js: /path/to/App.js: Duplicate __self prop found. You are most likely using the deprecated transform-react-jsx-self Babel plugin. 82 // 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. 83 useTransformReactJSXExperimental: true, 84 disableImportExportTransform: platformOptions.disableImportExportTransform, 85 lazyImportExportTransform: lazyImportsOption === true 86 ? (importModuleSpecifier) => { 87 // Do not lazy-initialize packages that are local imports (similar to `lazy: true` 88 // behavior) or are in the blacklist. 89 return !(importModuleSpecifier.includes('./') || lazyImports_1.lazyImports.has(importModuleSpecifier)); 90 } 91 : // Pass the option directly to `metro-react-native-babel-preset`, which in turn 92 // passes it to `babel-plugin-transform-modules-commonjs` 93 lazyImportsOption, 94 }, 95 ], 96 ], 97 plugins: [ 98 ...extraPlugins, 99 // TODO: Remove 100 [require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }], 101 require.resolve('@babel/plugin-proposal-export-namespace-from'), 102 // Automatically add `react-native-reanimated/plugin` when the package is installed. 103 // TODO: Move to be a customTransformOption. 104 hasModule('react-native-reanimated') && 105 reanimated !== false && [require.resolve('react-native-reanimated/plugin')], 106 ].filter(Boolean), 107 }; 108} 109function getAliasPlugin() { 110 if (!hasModule('@expo/vector-icons')) { 111 return null; 112 } 113 return [ 114 require.resolve('babel-plugin-module-resolver'), 115 { 116 alias: { 117 'react-native-vector-icons': '@expo/vector-icons', 118 }, 119 }, 120 ]; 121} 122function hasModule(name) { 123 try { 124 return !!require.resolve(name); 125 } 126 catch (error) { 127 if (error.code === 'MODULE_NOT_FOUND' && error.message.includes(name)) { 128 return false; 129 } 130 throw error; 131 } 132} 133/** Determine which bundler is being used. */ 134function getBundler(caller) { 135 if (!caller) 136 return null; 137 if (caller.bundler) 138 return caller.bundler; 139 if ( 140 // Known tools that use `webpack`-mode via `babel-loader`: `@expo/webpack-config`, Next.js <10 141 caller.name === 'babel-loader' || 142 // NextJS 11 uses this custom caller name. 143 caller.name === 'next-babel-turbo-loader') { 144 return 'webpack'; 145 } 146 // Assume anything else is Metro. 147 return 'metro'; 148} 149exports.default = babelPresetExpo; 150module.exports = babelPresetExpo; 151