mirror of
https://github.com/facebook/react-native.git
synced 2024-11-21 22:10:14 +00:00
Move react-native-babel-transformer and react-native-babel-preset from Metro to React Native repo (#38228)
Summary: X-link: https://github.com/facebook/metro/pull/1024 Pull Request resolved: https://github.com/facebook/react-native/pull/38228 Changelog: [General][Changed] - Move react-native-babel-transformer and react-native-babel-preset from Metro to React Native repo. Metro Changelog: **[Breaking]** - Remove `metro-react-native-babel-transformer` and `metro-react-native-babel-preset`, to be published as `react-native/metro-babel-transformer` and `react-native/babel-preset` instead. This diff does the following: - Move `metro/packages/metro-react-native-babel-preset` to `react-native/packages/react-native-babel-preset`. - Rename `metro-react-native-babel-preset` package to `react-native/babel-preset`. - Move `metro/packages/metro-react-native-babel-transformer` to `react-native/packages/react-native-babel-transformer`. - Rename `metro-react-native-babel-transformer` package to `react-native/metro-babel-transformer`. - Upadate dependencies. Reviewed By: robhogan Differential Revision: D46977466 fbshipit-source-id: 32478f63a0442b61a1804f12ef814c8b29d7f8bb
This commit is contained in:
parent
75b8b10765
commit
d380bb8473
2
.babelrc
2
.babelrc
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
"module:metro-react-native-babel-preset"
|
"module:@react-native/babel-preset"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"babel-plugin-transform-flow-enums"
|
"babel-plugin-transform-flow-enums"
|
||||||
|
@ -28,7 +28,7 @@ const nodeFiles = /[\\/]metro(?:-[^/]*)[\\/]/;
|
|||||||
// hook. This is used below to configure babelTransformSync under Jest.
|
// hook. This is used below to configure babelTransformSync under Jest.
|
||||||
const {only: _, ...nodeBabelOptions} = metroBabelRegister.config([]);
|
const {only: _, ...nodeBabelOptions} = metroBabelRegister.config([]);
|
||||||
|
|
||||||
const transformer = require('metro-react-native-babel-transformer');
|
const transformer = require('@react-native/metro-babel-transformer');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
process(src /*: string */, file /*: string */) /*: {code: string, ...} */ {
|
process(src /*: string */, file /*: string */) /*: {code: string, ...} */ {
|
||||||
@ -82,7 +82,7 @@ module.exports = {
|
|||||||
// $FlowFixMe[signature-verification-failure]
|
// $FlowFixMe[signature-verification-failure]
|
||||||
getCacheKey: createCacheKeyFunction([
|
getCacheKey: createCacheKeyFunction([
|
||||||
__filename,
|
__filename,
|
||||||
require.resolve('metro-react-native-babel-transformer'),
|
require.resolve('@react-native/metro-babel-transformer'),
|
||||||
require.resolve('@babel/core/package.json'),
|
require.resolve('@babel/core/package.json'),
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
"@babel/plugin-transform-regenerator": "^7.20.0",
|
"@babel/plugin-transform-regenerator": "^7.20.0",
|
||||||
"@definitelytyped/dtslint": "^0.0.127",
|
"@definitelytyped/dtslint": "^0.0.127",
|
||||||
"@jest/create-cache-key-function": "^29.2.1",
|
"@jest/create-cache-key-function": "^29.2.1",
|
||||||
|
"@react-native/metro-babel-transformer": "^0.73.11",
|
||||||
"@react-native/metro-config": "^0.73.0",
|
"@react-native/metro-config": "^0.73.0",
|
||||||
"@types/react": "^18.0.18",
|
"@types/react": "^18.0.18",
|
||||||
"@typescript-eslint/parser": "^5.57.1",
|
"@typescript-eslint/parser": "^5.57.1",
|
||||||
@ -85,7 +86,6 @@
|
|||||||
"jscodeshift": "^0.14.0",
|
"jscodeshift": "^0.14.0",
|
||||||
"metro-babel-register": "0.77.0",
|
"metro-babel-register": "0.77.0",
|
||||||
"metro-memory-fs": "0.77.0",
|
"metro-memory-fs": "0.77.0",
|
||||||
"metro-react-native-babel-transformer": "0.77.0",
|
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mock-fs": "^5.1.4",
|
"mock-fs": "^5.1.4",
|
||||||
"prettier": "2.8.8",
|
"prettier": "2.8.8",
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn add --dev @react-native/js-polyfills metro-config metro-react-native-babel-transformer metro-runtime @react-native/metro-config
|
yarn add --dev @react-native/js-polyfills metro-config @react-native/metro-babel-transformer metro-runtime @react-native/metro-config
|
||||||
```
|
```
|
||||||
|
|
||||||
*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like*
|
*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like*
|
||||||
|
@ -73,7 +73,7 @@ function getDefaultConfig(
|
|||||||
'metro-runtime/src/modules/asyncRequire',
|
'metro-runtime/src/modules/asyncRequire',
|
||||||
),
|
),
|
||||||
babelTransformerPath: require.resolve(
|
babelTransformerPath: require.resolve(
|
||||||
'metro-react-native-babel-transformer',
|
'@react-native/metro-babel-transformer',
|
||||||
),
|
),
|
||||||
getTransformOptions: async () => ({
|
getTransformOptions: async () => ({
|
||||||
transform: {
|
transform: {
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
},
|
},
|
||||||
"exports": "./index.js",
|
"exports": "./index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-native/metro-babel-transformer": "^0.73.11",
|
||||||
"@react-native/js-polyfills": "^0.73.0",
|
"@react-native/js-polyfills": "^0.73.0",
|
||||||
"metro-config": "0.77.0",
|
"metro-config": "0.77.0",
|
||||||
"metro-react-native-babel-transformer": "0.77.0",
|
|
||||||
"metro-runtime": "0.77.0"
|
"metro-runtime": "0.77.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
packages/react-native-babel-preset/.npmignore
Normal file
6
packages/react-native-babel-preset/.npmignore
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
**/__mocks__/
|
||||||
|
**/__tests__/
|
||||||
|
/build/
|
||||||
|
/src.real/
|
||||||
|
/types/
|
||||||
|
yarn.lock
|
41
packages/react-native-babel-preset/README.md
Normal file
41
packages/react-native-babel-preset/README.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# @react-native/babel-preset
|
||||||
|
|
||||||
|
Babel presets for [React Native](https://reactnative.dev) applications. React Native itself uses this Babel preset by default when transforming your app's source code.
|
||||||
|
|
||||||
|
If you wish to use a custom Babel configuration by writing a `babel.config.js` file in your project's root directory, you must specify all the plugins necessary to transform your code. React Native does not apply its default Babel configuration in this case. So, to make your life easier, you can use this preset to get the default configuration and then specify more plugins that run before it.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
As mentioned above, you only need to use this preset if you are writing a custom `babel.config.js` file.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
Install `@react-native/babel-preset` in your app:
|
||||||
|
|
||||||
|
with `npm`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i @react-native/babel-preset --save-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
or with `yarn`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add -D @react-native/babel-preset
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring Babel
|
||||||
|
|
||||||
|
Then, create a file called `babel.config.js` in your project's root directory. The existence of this `babel.config.js` file will tell React Native to use your custom Babel configuration instead of its own. Then load this preset:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"presets": ["module:@react-native/babel-preset"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can further customize your Babel configuration by specifying plugins and other options. See [Babel's `babel.config.js` documentation](https://babeljs.io/docs/en/config-files/) to learn more.
|
||||||
|
|
||||||
|
## Help and Support
|
||||||
|
|
||||||
|
If you get stuck configuring Babel, please ask a question on Stack Overflow or find a consultant for help. If you discover a bug, please open up an issue.
|
63
packages/react-native-babel-preset/package.json
Normal file
63
packages/react-native-babel-preset/package.json
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"name": "@react-native/babel-preset",
|
||||||
|
"version": "0.73.15",
|
||||||
|
"description": "Babel preset for React Native applications",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@github.com:facebook/react-native.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"babel",
|
||||||
|
"preset",
|
||||||
|
"react-native"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/core": "^7.20.0",
|
||||||
|
"@babel/plugin-proposal-async-generator-functions": "^7.0.0",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.18.0",
|
||||||
|
"@babel/plugin-proposal-export-default-from": "^7.0.0",
|
||||||
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0",
|
||||||
|
"@babel/plugin-proposal-numeric-separator": "^7.0.0",
|
||||||
|
"@babel/plugin-proposal-object-rest-spread": "^7.20.0",
|
||||||
|
"@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
|
||||||
|
"@babel/plugin-proposal-optional-chaining": "^7.20.0",
|
||||||
|
"@babel/plugin-syntax-dynamic-import": "^7.8.0",
|
||||||
|
"@babel/plugin-syntax-export-default-from": "^7.0.0",
|
||||||
|
"@babel/plugin-syntax-flow": "^7.18.0",
|
||||||
|
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0",
|
||||||
|
"@babel/plugin-syntax-optional-chaining": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-arrow-functions": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-async-to-generator": "^7.20.0",
|
||||||
|
"@babel/plugin-transform-block-scoping": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-classes": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-computed-properties": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-destructuring": "^7.20.0",
|
||||||
|
"@babel/plugin-transform-flow-strip-types": "^7.20.0",
|
||||||
|
"@babel/plugin-transform-function-name": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-literals": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-modules-commonjs": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-parameters": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-react-display-name": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-react-jsx": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-react-jsx-self": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-react-jsx-source": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-shorthand-properties": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-spread": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-sticky-regex": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-typescript": "^7.5.0",
|
||||||
|
"@babel/plugin-transform-unicode-regex": "^7.0.0",
|
||||||
|
"@babel/template": "^7.0.0",
|
||||||
|
"babel-plugin-transform-flow-enums": "^0.0.2",
|
||||||
|
"react-refresh": "^0.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "*"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
}
|
17
packages/react-native-babel-preset/src/configs/hmr.js
vendored
Normal file
17
packages/react-native-babel-preset/src/configs/hmr.js
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
* @oncall react_native
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
return {
|
||||||
|
plugins: [require('react-refresh/babel')],
|
||||||
|
};
|
||||||
|
};
|
93
packages/react-native-babel-preset/src/configs/lazy-imports.js
vendored
Normal file
93
packages/react-native-babel-preset/src/configs/lazy-imports.js
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
* @oncall react_native
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This is the set of modules that React Native publicly exports and that we
|
||||||
|
// want to require lazily. Keep this list in sync with
|
||||||
|
// react-native/index.js (though having extra entries here is fairly harmless).
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = new Set([
|
||||||
|
'AccessibilityInfo',
|
||||||
|
'ActivityIndicator',
|
||||||
|
'Button',
|
||||||
|
'DatePickerIOS',
|
||||||
|
'DrawerLayoutAndroid',
|
||||||
|
'FlatList',
|
||||||
|
'Image',
|
||||||
|
'ImageBackground',
|
||||||
|
'InputAccessoryView',
|
||||||
|
'KeyboardAvoidingView',
|
||||||
|
'Modal',
|
||||||
|
'Pressable',
|
||||||
|
'ProgressBarAndroid',
|
||||||
|
'ProgressViewIOS',
|
||||||
|
'SafeAreaView',
|
||||||
|
'ScrollView',
|
||||||
|
'SectionList',
|
||||||
|
'Slider',
|
||||||
|
'Switch',
|
||||||
|
'RefreshControl',
|
||||||
|
'StatusBar',
|
||||||
|
'Text',
|
||||||
|
'TextInput',
|
||||||
|
'Touchable',
|
||||||
|
'TouchableHighlight',
|
||||||
|
'TouchableNativeFeedback',
|
||||||
|
'TouchableOpacity',
|
||||||
|
'TouchableWithoutFeedback',
|
||||||
|
'View',
|
||||||
|
'VirtualizedList',
|
||||||
|
'VirtualizedSectionList',
|
||||||
|
|
||||||
|
// APIs
|
||||||
|
'ActionSheetIOS',
|
||||||
|
'Alert',
|
||||||
|
'Animated',
|
||||||
|
'Appearance',
|
||||||
|
'AppRegistry',
|
||||||
|
'AppState',
|
||||||
|
'AsyncStorage',
|
||||||
|
'BackHandler',
|
||||||
|
'Clipboard',
|
||||||
|
'DeviceInfo',
|
||||||
|
'Dimensions',
|
||||||
|
'Easing',
|
||||||
|
'ReactNative',
|
||||||
|
'I18nManager',
|
||||||
|
'InteractionManager',
|
||||||
|
'Keyboard',
|
||||||
|
'LayoutAnimation',
|
||||||
|
'Linking',
|
||||||
|
'LogBox',
|
||||||
|
'NativeEventEmitter',
|
||||||
|
'PanResponder',
|
||||||
|
'PermissionsAndroid',
|
||||||
|
'PixelRatio',
|
||||||
|
'PushNotificationIOS',
|
||||||
|
'Settings',
|
||||||
|
'Share',
|
||||||
|
'StyleSheet',
|
||||||
|
'Systrace',
|
||||||
|
'ToastAndroid',
|
||||||
|
'TVEventHandler',
|
||||||
|
'UIManager',
|
||||||
|
'ReactNative',
|
||||||
|
'UTFSequence',
|
||||||
|
'Vibration',
|
||||||
|
|
||||||
|
// Plugins
|
||||||
|
'RCTDeviceEventEmitter',
|
||||||
|
'RCTNativeAppEventEmitter',
|
||||||
|
'NativeModules',
|
||||||
|
'Platform',
|
||||||
|
'processColor',
|
||||||
|
'requireNativeComponent',
|
||||||
|
]);
|
215
packages/react-native-babel-preset/src/configs/main.js
vendored
Normal file
215
packages/react-native-babel-preset/src/configs/main.js
vendored
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
* @oncall react_native
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const passthroughSyntaxPlugins = require('../passthrough-syntax-plugins');
|
||||||
|
const lazyImports = require('./lazy-imports');
|
||||||
|
|
||||||
|
function isTypeScriptSource(fileName) {
|
||||||
|
return !!fileName && fileName.endsWith('.ts');
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTSXSource(fileName) {
|
||||||
|
return !!fileName && fileName.endsWith('.tsx');
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultPlugins = [
|
||||||
|
[require('@babel/plugin-syntax-flow')],
|
||||||
|
[require('babel-plugin-transform-flow-enums')],
|
||||||
|
[require('@babel/plugin-transform-block-scoping')],
|
||||||
|
[
|
||||||
|
require('@babel/plugin-proposal-class-properties'),
|
||||||
|
// use `this.foo = bar` instead of `this.defineProperty('foo', ...)`
|
||||||
|
{loose: true},
|
||||||
|
],
|
||||||
|
[require('@babel/plugin-syntax-dynamic-import')],
|
||||||
|
[require('@babel/plugin-syntax-export-default-from')],
|
||||||
|
...passthroughSyntaxPlugins,
|
||||||
|
[require('@babel/plugin-transform-unicode-regex')],
|
||||||
|
];
|
||||||
|
|
||||||
|
const getPreset = (src, options) => {
|
||||||
|
const transformProfile =
|
||||||
|
(options && options.unstable_transformProfile) || 'default';
|
||||||
|
const isHermesStable = transformProfile === 'hermes-stable';
|
||||||
|
const isHermesCanary = transformProfile === 'hermes-canary';
|
||||||
|
const isHermes = isHermesStable || isHermesCanary;
|
||||||
|
|
||||||
|
const isNull = src == null;
|
||||||
|
const hasClass = isNull || src.indexOf('class') !== -1;
|
||||||
|
|
||||||
|
const extraPlugins = [];
|
||||||
|
if (!options.useTransformReactJSXExperimental) {
|
||||||
|
extraPlugins.push([
|
||||||
|
require('@babel/plugin-transform-react-jsx'),
|
||||||
|
{runtime: 'automatic'},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options || !options.disableImportExportTransform) {
|
||||||
|
extraPlugins.push(
|
||||||
|
[require('@babel/plugin-proposal-export-default-from')],
|
||||||
|
[
|
||||||
|
require('@babel/plugin-transform-modules-commonjs'),
|
||||||
|
{
|
||||||
|
strict: false,
|
||||||
|
strictMode: false, // prevent "use strict" injections
|
||||||
|
lazy:
|
||||||
|
options && options.lazyImportExportTransform != null
|
||||||
|
? options.lazyImportExportTransform
|
||||||
|
: importSpecifier => lazyImports.has(importSpecifier),
|
||||||
|
allowTopLevelThis: true, // dont rewrite global `this` -> `undefined`
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasClass) {
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-classes')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(gaearon): put this back into '=>' indexOf bailout
|
||||||
|
// and patch react-refresh to not depend on this transform.
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-arrow-functions')]);
|
||||||
|
|
||||||
|
if (!isHermes) {
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-computed-properties')]);
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-parameters')]);
|
||||||
|
extraPlugins.push([
|
||||||
|
require('@babel/plugin-transform-shorthand-properties'),
|
||||||
|
]);
|
||||||
|
extraPlugins.push([
|
||||||
|
require('@babel/plugin-proposal-optional-catch-binding'),
|
||||||
|
]);
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-function-name')]);
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-literals')]);
|
||||||
|
extraPlugins.push([require('@babel/plugin-proposal-numeric-separator')]);
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-sticky-regex')]);
|
||||||
|
} else {
|
||||||
|
extraPlugins.push([
|
||||||
|
require('@babel/plugin-transform-named-capturing-groups-regex'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (!isHermesCanary) {
|
||||||
|
extraPlugins.push([
|
||||||
|
require('@babel/plugin-transform-destructuring'),
|
||||||
|
{useBuiltIns: true},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (!isHermes && (isNull || hasClass || src.indexOf('...') !== -1)) {
|
||||||
|
extraPlugins.push(
|
||||||
|
[require('@babel/plugin-transform-spread')],
|
||||||
|
[
|
||||||
|
require('@babel/plugin-proposal-object-rest-spread'),
|
||||||
|
// Assume no dependence on getters or evaluation order. See https://github.com/babel/babel/pull/11520
|
||||||
|
{loose: true, useBuiltIns: true},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isNull || src.indexOf('async') !== -1) {
|
||||||
|
extraPlugins.push([
|
||||||
|
require('@babel/plugin-proposal-async-generator-functions'),
|
||||||
|
]);
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-async-to-generator')]);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
isNull ||
|
||||||
|
src.indexOf('React.createClass') !== -1 ||
|
||||||
|
src.indexOf('createReactClass') !== -1
|
||||||
|
) {
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-react-display-name')]);
|
||||||
|
}
|
||||||
|
if (!isHermes && (isNull || src.indexOf('?.') !== -1)) {
|
||||||
|
extraPlugins.push([
|
||||||
|
require('@babel/plugin-proposal-optional-chaining'),
|
||||||
|
{loose: true},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (!isHermes && (isNull || src.indexOf('??') !== -1)) {
|
||||||
|
extraPlugins.push([
|
||||||
|
require('@babel/plugin-proposal-nullish-coalescing-operator'),
|
||||||
|
{loose: true},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options && options.dev && !options.useTransformReactJSXExperimental) {
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-react-jsx-source')]);
|
||||||
|
extraPlugins.push([require('@babel/plugin-transform-react-jsx-self')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options || options.enableBabelRuntime !== false) {
|
||||||
|
// Allows configuring a specific runtime version to optimize output
|
||||||
|
const isVersion = typeof options?.enableBabelRuntime === 'string';
|
||||||
|
|
||||||
|
extraPlugins.push([
|
||||||
|
require('@babel/plugin-transform-runtime'),
|
||||||
|
{
|
||||||
|
helpers: true,
|
||||||
|
regenerator: !isHermes,
|
||||||
|
...(isVersion && {version: options.enableBabelRuntime}),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
comments: false,
|
||||||
|
compact: true,
|
||||||
|
overrides: [
|
||||||
|
// the flow strip types plugin must go BEFORE class properties!
|
||||||
|
// there'll be a test case that fails if you don't.
|
||||||
|
{
|
||||||
|
plugins: [require('@babel/plugin-transform-flow-strip-types')],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plugins: defaultPlugins,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: isTypeScriptSource,
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
require('@babel/plugin-transform-typescript'),
|
||||||
|
{
|
||||||
|
isTSX: false,
|
||||||
|
allowNamespaces: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: isTSXSource,
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
require('@babel/plugin-transform-typescript'),
|
||||||
|
{
|
||||||
|
isTSX: true,
|
||||||
|
allowNamespaces: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plugins: extraPlugins,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = options => {
|
||||||
|
if (options.withDevTools == null) {
|
||||||
|
const env = process.env.BABEL_ENV || process.env.NODE_ENV;
|
||||||
|
if (!env || env === 'development') {
|
||||||
|
return getPreset(null, {...options, dev: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getPreset(null, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.getPreset = getPreset;
|
20
packages/react-native-babel-preset/src/index.js
vendored
Normal file
20
packages/react-native-babel-preset/src/index.js
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
* @oncall react_native
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const main = require('./configs/main');
|
||||||
|
|
||||||
|
module.exports = function (babel, options) {
|
||||||
|
return main(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.getPreset = main.getPreset;
|
||||||
|
module.exports.passthroughSyntaxPlugins = require('./passthrough-syntax-plugins');
|
23
packages/react-native-babel-preset/src/passthrough-syntax-plugins.js
vendored
Normal file
23
packages/react-native-babel-preset/src/passthrough-syntax-plugins.js
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
* @oncall react_native
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// This list of syntax plugins is used for two purposes:
|
||||||
|
// 1. Enabling experimental syntax features in the INPUT to the Metro Babel
|
||||||
|
// transformer, regardless of whether we actually transform them.
|
||||||
|
// 2. Enabling these same features in parser passes that consume the OUTPUT of
|
||||||
|
// the Metro Babel transformer.
|
||||||
|
const passthroughSyntaxPlugins = [
|
||||||
|
[require('@babel/plugin-syntax-nullish-coalescing-operator')],
|
||||||
|
[require('@babel/plugin-syntax-optional-chaining')],
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports = passthroughSyntaxPlugins;
|
6
packages/react-native-babel-transformer/.npmignore
Normal file
6
packages/react-native-babel-transformer/.npmignore
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
**/__mocks__/
|
||||||
|
**/__tests__/
|
||||||
|
/build/
|
||||||
|
/src.real/
|
||||||
|
/types/
|
||||||
|
yarn.lock
|
30
packages/react-native-babel-transformer/package.json
Normal file
30
packages/react-native-babel-transformer/package.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@react-native/metro-babel-transformer",
|
||||||
|
"version": "0.73.11",
|
||||||
|
"description": "Babel transformer for React Native applications.",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@github.com:facebook/react-native.git",
|
||||||
|
"directory": "packages/react-native-babel-transformer"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"transformer",
|
||||||
|
"react-native",
|
||||||
|
"metro"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/core": "^7.20.0",
|
||||||
|
"@react-native/babel-preset": "*",
|
||||||
|
"babel-preset-fbjs": "^3.4.0",
|
||||||
|
"hermes-parser": "0.15.0",
|
||||||
|
"nullthrows": "^1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "*"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
}
|
53
packages/react-native-babel-transformer/src/__tests__/transform-test.js
vendored
Normal file
53
packages/react-native-babel-transformer/src/__tests__/transform-test.js
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @flow strict-local
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const {transform} = require('../index.js');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const PROJECT_ROOT = path.sep === '/' ? '/my/project' : 'C:\\my\\project';
|
||||||
|
|
||||||
|
it('exposes the correct absolute path to a source file to plugins', () => {
|
||||||
|
let visitorFilename;
|
||||||
|
let pluginCwd;
|
||||||
|
transform({
|
||||||
|
filename: 'foo.js',
|
||||||
|
src: 'console.log("foo");',
|
||||||
|
plugins: [
|
||||||
|
(babel, opts, cwd) => {
|
||||||
|
pluginCwd = cwd;
|
||||||
|
return {
|
||||||
|
visitor: {
|
||||||
|
CallExpression: {
|
||||||
|
enter: (_, state) => {
|
||||||
|
visitorFilename = state.filename;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
dev: true,
|
||||||
|
enableBabelRuntime: false,
|
||||||
|
enableBabelRCLookup: false,
|
||||||
|
globalPrefix: '__metro__',
|
||||||
|
hot: false,
|
||||||
|
inlineRequires: false,
|
||||||
|
minify: false,
|
||||||
|
platform: null,
|
||||||
|
publicPath: 'test',
|
||||||
|
projectRoot: PROJECT_ROOT,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(pluginCwd).toEqual(PROJECT_ROOT);
|
||||||
|
expect(visitorFilename).toEqual(path.resolve(PROJECT_ROOT, 'foo.js'));
|
||||||
|
});
|
255
packages/react-native-babel-transformer/src/index.js
vendored
Normal file
255
packages/react-native-babel-transformer/src/index.js
vendored
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
* @format
|
||||||
|
* @oncall react_native
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This file uses Flow comment syntax so that it may be used from source as a
|
||||||
|
// transformer without itself requiring transformation, such as in
|
||||||
|
// facebook/react-native's own tests.
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*::
|
||||||
|
import type {BabelCoreOptions, Plugins, TransformResult} from '@babel/core';
|
||||||
|
import type {
|
||||||
|
BabelTransformer,
|
||||||
|
MetroBabelFileMetadata,
|
||||||
|
} from 'metro-babel-transformer';
|
||||||
|
*/
|
||||||
|
|
||||||
|
const {parseSync, transformFromAstSync} = require('@babel/core');
|
||||||
|
const inlineRequiresPlugin = require('babel-preset-fbjs/plugins/inline-requires');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const fs = require('fs');
|
||||||
|
const makeHMRConfig = require('@react-native/babel-preset/src/configs/hmr');
|
||||||
|
const nullthrows = require('nullthrows');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const cacheKeyParts = [
|
||||||
|
fs.readFileSync(__filename),
|
||||||
|
require('babel-preset-fbjs/package.json').version,
|
||||||
|
];
|
||||||
|
|
||||||
|
// TS detection conditions copied from @react-native/babel-preset
|
||||||
|
function isTypeScriptSource(fileName /*: string */) {
|
||||||
|
return !!fileName && fileName.endsWith('.ts');
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTSXSource(fileName /*: string */) {
|
||||||
|
return !!fileName && fileName.endsWith('.tsx');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a memoized function that checks for the existence of a
|
||||||
|
* project level .babelrc file, and if it doesn't exist, reads the
|
||||||
|
* default RN babelrc file and uses that.
|
||||||
|
*/
|
||||||
|
const getBabelRC = (function () {
|
||||||
|
let babelRC /*: ?BabelCoreOptions */ = null;
|
||||||
|
|
||||||
|
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
|
||||||
|
* LTI update could not be added via codemod */
|
||||||
|
return function _getBabelRC({
|
||||||
|
projectRoot,
|
||||||
|
extendsBabelConfigPath,
|
||||||
|
...options
|
||||||
|
}) {
|
||||||
|
if (babelRC != null) {
|
||||||
|
return babelRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
babelRC = {
|
||||||
|
plugins: [],
|
||||||
|
extends: extendsBabelConfigPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (extendsBabelConfigPath) {
|
||||||
|
return babelRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's look for a babel config file in the project root.
|
||||||
|
let projectBabelRCPath;
|
||||||
|
|
||||||
|
// .babelrc
|
||||||
|
if (projectRoot) {
|
||||||
|
projectBabelRCPath = path.resolve(projectRoot, '.babelrc');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectBabelRCPath) {
|
||||||
|
// .babelrc.js
|
||||||
|
if (!fs.existsSync(projectBabelRCPath)) {
|
||||||
|
projectBabelRCPath = path.resolve(projectRoot, '.babelrc.js');
|
||||||
|
}
|
||||||
|
|
||||||
|
// babel.config.js
|
||||||
|
if (!fs.existsSync(projectBabelRCPath)) {
|
||||||
|
projectBabelRCPath = path.resolve(projectRoot, 'babel.config.js');
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found a babel config file, extend our config off of it
|
||||||
|
// otherwise the default config will be used
|
||||||
|
if (fs.existsSync(projectBabelRCPath)) {
|
||||||
|
// $FlowFixMe[incompatible-use] `extends` is missing in null or undefined.
|
||||||
|
babelRC.extends = projectBabelRCPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a babel config file doesn't exist in the project then
|
||||||
|
// the default preset for react-native will be used instead.
|
||||||
|
// $FlowFixMe[incompatible-use] `extends` is missing in null or undefined.
|
||||||
|
// $FlowFixMe[incompatible-type] `extends` is missing in null or undefined.
|
||||||
|
if (!babelRC.extends) {
|
||||||
|
const {experimentalImportSupport, ...presetOptions} = options;
|
||||||
|
|
||||||
|
// $FlowFixMe[incompatible-use] `presets` is missing in null or undefined.
|
||||||
|
babelRC.presets = [
|
||||||
|
[
|
||||||
|
require('@react-native/babel-preset'),
|
||||||
|
{
|
||||||
|
projectRoot,
|
||||||
|
...presetOptions,
|
||||||
|
disableImportExportTransform: experimentalImportSupport,
|
||||||
|
enableBabelRuntime: options.enableBabelRuntime,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return babelRC;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a filename and options, build a Babel
|
||||||
|
* config object with the appropriate plugins.
|
||||||
|
*/
|
||||||
|
function buildBabelConfig(
|
||||||
|
filename /*: string */,
|
||||||
|
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
|
||||||
|
* LTI update could not be added via codemod */
|
||||||
|
options,
|
||||||
|
plugins /*:: ?: Plugins*/ = [],
|
||||||
|
) /*: BabelCoreOptions*/ {
|
||||||
|
const babelRC = getBabelRC(options);
|
||||||
|
|
||||||
|
const extraConfig /*: BabelCoreOptions */ = {
|
||||||
|
babelrc:
|
||||||
|
typeof options.enableBabelRCLookup === 'boolean'
|
||||||
|
? options.enableBabelRCLookup
|
||||||
|
: true,
|
||||||
|
code: false,
|
||||||
|
cwd: options.projectRoot,
|
||||||
|
filename,
|
||||||
|
highlightCode: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let config /*: BabelCoreOptions */ = {
|
||||||
|
...babelRC,
|
||||||
|
...extraConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add extra plugins
|
||||||
|
const extraPlugins = [];
|
||||||
|
|
||||||
|
if (options.inlineRequires) {
|
||||||
|
extraPlugins.push(inlineRequiresPlugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
const withExtrPlugins = (config.plugins = extraPlugins.concat(
|
||||||
|
config.plugins,
|
||||||
|
plugins,
|
||||||
|
));
|
||||||
|
|
||||||
|
if (options.dev && options.hot) {
|
||||||
|
// Note: this intentionally doesn't include the path separator because
|
||||||
|
// I'm not sure which one it should use on Windows, and false positives
|
||||||
|
// are unlikely anyway. If you later decide to include the separator,
|
||||||
|
// don't forget that the string usually *starts* with "node_modules" so
|
||||||
|
// the first one often won't be there.
|
||||||
|
const mayContainEditableReactComponents =
|
||||||
|
filename.indexOf('node_modules') === -1;
|
||||||
|
|
||||||
|
if (mayContainEditableReactComponents) {
|
||||||
|
const hmrConfig = makeHMRConfig();
|
||||||
|
hmrConfig.plugins = withExtrPlugins.concat(hmrConfig.plugins);
|
||||||
|
config = {...config, ...hmrConfig};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...babelRC,
|
||||||
|
...config,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const transform /*: BabelTransformer['transform'] */ = ({
|
||||||
|
filename,
|
||||||
|
options,
|
||||||
|
src,
|
||||||
|
plugins,
|
||||||
|
}) => {
|
||||||
|
const OLD_BABEL_ENV = process.env.BABEL_ENV;
|
||||||
|
process.env.BABEL_ENV = options.dev
|
||||||
|
? 'development'
|
||||||
|
: process.env.BABEL_ENV || 'production';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const babelConfig = {
|
||||||
|
// ES modules require sourceType='module' but OSS may not always want that
|
||||||
|
sourceType: 'unambiguous',
|
||||||
|
...buildBabelConfig(filename, options, plugins),
|
||||||
|
caller: {name: 'metro', bundler: 'metro', platform: options.platform},
|
||||||
|
ast: true,
|
||||||
|
|
||||||
|
// NOTE(EvanBacon): We split the parse/transform steps up to accommodate
|
||||||
|
// Hermes parsing, but this defaults to cloning the AST which increases
|
||||||
|
// the transformation time by a fair amount.
|
||||||
|
// You get this behavior by default when using Babel's `transform` method directly.
|
||||||
|
cloneInputAst: false,
|
||||||
|
};
|
||||||
|
const sourceAst =
|
||||||
|
isTypeScriptSource(filename) ||
|
||||||
|
isTSXSource(filename) ||
|
||||||
|
!options.hermesParser
|
||||||
|
? parseSync(src, babelConfig)
|
||||||
|
: require('hermes-parser').parse(src, {
|
||||||
|
babel: true,
|
||||||
|
sourceType: babelConfig.sourceType,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result /*: TransformResult<MetroBabelFileMetadata> */ =
|
||||||
|
transformFromAstSync(sourceAst, src, babelConfig);
|
||||||
|
|
||||||
|
// The result from `transformFromAstSync` can be null (if the file is ignored)
|
||||||
|
if (!result) {
|
||||||
|
/* $FlowFixMe BabelTransformer specifies that the `ast` can never be null but
|
||||||
|
* the function returns here. Discovered when typing `BabelNode`. */
|
||||||
|
return {ast: null};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {ast: nullthrows(result.ast), metadata: result.metadata};
|
||||||
|
} finally {
|
||||||
|
if (OLD_BABEL_ENV) {
|
||||||
|
process.env.BABEL_ENV = OLD_BABEL_ENV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getCacheKey() {
|
||||||
|
var key = crypto.createHash('md5');
|
||||||
|
cacheKeyParts.forEach(part => key.update(part));
|
||||||
|
return key.digest('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
const babelTransformer /*: BabelTransformer */ = {
|
||||||
|
transform,
|
||||||
|
getCacheKey,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = babelTransformer;
|
@ -1,3 +1,3 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: ['module:metro-react-native-babel-preset'],
|
presets: ['module:@react-native/babel-preset'],
|
||||||
};
|
};
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"@babel/core": "^7.20.0",
|
"@babel/core": "^7.20.0",
|
||||||
"@babel/preset-env": "^7.20.0",
|
"@babel/preset-env": "^7.20.0",
|
||||||
"@babel/runtime": "^7.20.0",
|
"@babel/runtime": "^7.20.0",
|
||||||
|
"@react-native/babel-preset": "^0.73.15",
|
||||||
"@react-native/eslint-config": "^0.73.0",
|
"@react-native/eslint-config": "^0.73.0",
|
||||||
"@react-native/metro-config": "^0.73.0",
|
"@react-native/metro-config": "^0.73.0",
|
||||||
"@react-native/typescript-config": "^0.73.0",
|
"@react-native/typescript-config": "^0.73.0",
|
||||||
@ -25,7 +26,6 @@
|
|||||||
"babel-jest": "^29.2.1",
|
"babel-jest": "^29.2.1",
|
||||||
"eslint": "^8.19.0",
|
"eslint": "^8.19.0",
|
||||||
"jest": "^29.2.1",
|
"jest": "^29.2.1",
|
||||||
"metro-react-native-babel-preset": "0.76.7",
|
|
||||||
"prettier": "2.8.8",
|
"prettier": "2.8.8",
|
||||||
"react-test-renderer": "18.2.0",
|
"react-test-renderer": "18.2.0",
|
||||||
"typescript": "5.0.4"
|
"typescript": "5.0.4"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
"module:metro-react-native-babel-preset"
|
"module:@react-native/babel-preset"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"babel-plugin-transform-flow-enums"
|
"babel-plugin-transform-flow-enums"
|
||||||
|
Loading…
Reference in New Issue
Block a user