This is an example project to demonstrate the issue with esbuild and Hermes-compiled code. Due to certain esbuild optimizations, Hermes generates more bytecode compared to the standard Metro bundle.
It hepens for me with the folowing case:
I use styled-components
and react-native-gesture-handler
and found that then more I have react-native-gesture-handler
components wrapped into styled
the more my hermes output bundle.
It seems the problem not in the styled-components
and react-native-gesture-handler
themself but more esbuild
and hermes
.
The problem can be boiled down to the following code:
// TouchableOpacity.tsx
let Reanimated;
try {
Reanimated = require('react-native-reanimated');
} catch (e) {
Reanimated = undefined;
}
export const TouchableOpacity = ({ children }) => {
Reanimated.useSharedValue(0);
return children;
};
// index.tsx
const { TouchableOpacity } from './TouchableOpacity'
const styled = (Component: React.ComponentType) => (styles: any) => {
return (props: any) => <Component {...props} style={styles} />;
};
// input
const Comp = styled(View)``;
// output
// var _a;
// const Comp = styled(View)(_a || (_a = null));
It seems that the combination of _a || (_a = null)
and (this part in the react-native-gesture-handler
lib ) are contributing to the large bundle size.
- Run the script
yarn copy-modules
. This will generate 1000 copies of the./src/template.tsx
file. - Run
ESBUILD=true yarn build
to create the esbuild bundle. - Check the size of the
./output/index.android.bundle.hrs
Hermes bundle. - Run
ESBUILD=true yarn build
to create the metro bundle. - Check the size of the
./output/index.android.bundle.hrs
Hermes bundle.
Expected Result (ER): The size of the esbuild bundle should be less than or equal to the size of the Metro bundle.
Actual Result (AR): The size of the esbuild bundle (~2.7MB) is much larger than the bundle (~1.3MB) produced by Metro.