metro
metro copied to clipboard
inlineRequires: true not working on default exports/imports
Do you want to request a feature or report a bug? Bug
What is the current behavior?
When setting inlineRequires
to true
, I'd expect all imports to be transformed to inline requires. However, it seems like this is not working for default exports. Check out the following example:
// metro.config.js
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
}),
},
};
// defaultFn.js
console.log('defaultFn.js imported');
export default function defaultFn() {
console.log('defaultFn executed');
}
// namedFn.js
console.log('namedFn.js imported');
export function namedFn() {
console.log('namedFn executed');
}
// index.js
import React from 'react';
import { AppRegistry, Button, SafeAreaView } from 'react-native';
import { name } from './app.json';
import { namedFn } from './namedFn';
import defaultFn from './defaultFn';
function App() {
const onPress = () => {
namedFn();
defaultFn();
};
return (
<SafeAreaView>
<Button title="Click me" onPress={onPress} />
</SafeAreaView>
);
}
AppRegistry.registerComponent(name, () => App);
When launching the app, I immediately get the following logs:
defaultFn.js imported
After pressing the button, the following is logged:
namedFn.js imported
namedFn executed
defaultFn executed
What is the expected behavior?
I would expect the defaultFn.js imported
log to also occur only after pressing the button. The log indicates that the defaultFn.js
file is imported and parsed, and inlineRequires: true
is not behaving correctly? Or is this by design?
Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system.
- react-native 0.70.6
- node 16.16.0
- npm 8.16.0
- MacOS
Thanks @robrechtme! This is a known issue. experimentalImportSupport: true
solves this, but the option is currently undocumented and experimental (as reflected in its name). We're looking into what it would involve to make it the default behaviour in Metro.
Hi @motiz88
Are you sure? Changing experimentalImportSupport
has no effect on my example.
I'm using [email protected]
which resolves metro to:
metro-react-native-babel-transformer "0.72.3"
metro-runtime "0.72.3"
metro-source-map "0.72.3"
Hi @motiz88,
I'm seeing the same as @robrechtme.
Both experimentalImportSupport
and inlineRequires
are set to true
, but the default exports are never transformed to inline requires. I also verify this by setting a console.log()
top-level in a component file.
When default exporting the component, the console.log()
is always executed immediately (so no inline require happens). But when "regularly" exporting the component, the console.log()
is only executed when rendered.
This is rather annoying, since most of our components are exported as defaults.
I even converted all our default exports to regular exports, just to be able to profit from this feature (hundreds of components) 😅
@robrechtme (and @bitcrumb): Is there a babel.config.js
file in your project? One quirk of the current implementation of experimentalImportSupport: true
is that it depends on disabling Babel's ES Module support, which you may need to do manually at the moment.
There is in ours, but it's rather limited:
module.exports = function babelConfig(api) {
api.cache.using(() => process.env.NODE_ENV);
const presets = ['module:metro-react-native-babel-preset'];
const plugins = ['react-native-reanimated/plugin'];
if (!(api.env('development') || api.env('test'))) {
plugins.push('transform-remove-console');
}
plugins.push([
require.resolve('babel-plugin-module-resolver'),
{
root: ['./src/'],
alias: {
...
},
},
]);
return {
presets,
plugins,
};
};
How exactly do I disable Babel ES Module support?
👀
I could reproduce this in a fresh RN app with npx react-native init
, there the babel config is:
// babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};
How fix it via custom resolver?
I even converted all our default exports to regular exports, just to be able to profit from this feature (hundreds of components) 😅
Hey @bitcrumb , did you measure improvements? We also often use default export, I'm wondering how beneficial it is to switch to a named export.