metro icon indicating copy to clipboard operation
metro copied to clipboard

Named and default exports have different resolving strategies/behaviors

Open Yooooomi opened this issue 1 year ago • 5 comments

Problem

Hello! Lately I've been working on optimizing the startup time of our application. I learned a lot about how hermes works and how it incrementally resolves imports as we use the values. I followed this snippet to analyze how many modules were loaded at the Home page of our page and realized it was way too high (5300, which is crazy).

After many attempts at understanding why it would resolve flows and components that were not required in the Home page, I found that Hermes resolves default export by default. Plus the fact that it will initialize data and allocate to memory currently unwanted stuff and execute top level code.

Explanation:

// FileB.tsx
import {View} from "react-native";

console.log("This will log before first render");

export default function ComponentB() {
  return <View />;
}

// FileA.tsx
import ComponentB from "./FileB";

export default function ComponentA() {
  return <ComponentB />;
}

// App.tsx
import ComponentA from "./FileA";

// Insert here the snippet provided above
// The snippet will log that FileB is resolved and loaded

export default function App() {
  return <ComponentA />;
}

Whereas

// FileB.tsx
import {View} from "react-native";

console.log("This will NOT log before first render");

export function ComponentB() {
  return <View />;
}

// FileA.tsx
import {ComponentB} from "./FileB";

export function ComponentA() {
  return <ComponentB />;
}

// App.tsx
import {ComponentA} from "./FileA";

// Insert here the snippet provided above
// The snippet will log that FileA is resolved and loaded but **not** FileB

export default function App() {
  return <ComponentA />;
}

has a completely different behavior.

Is this behavior wanted or not? I feel like I should rewrite all the imports to named imports to work this around. But would be happy to know if there is any other way and if not why it's technically not possible.

Thanks for your answers.

Yooooomi avatar Sep 29 '23 08:09 Yooooomi

:warning: Missing Reproducible Example
:information_source: We could not detect a reproducible example in your issue report. Please provide either:
  • If your bug is UI related: a Snack
  • If your bug is build/update related: use our Reproducer Template. A reproducer needs to be in a GitHub repository under your username.

github-actions[bot] avatar Sep 29 '23 23:09 github-actions[bot]

:warning: Missing Reproducible Example
:information_source: We could not detect a reproducible example in your issue report. Please provide either:
  • If your bug is UI related: a Snack
  • If your bug is build/update related: use our Reproducer Template. A reproducer needs to be in a GitHub repository under your username.

github-actions[bot] avatar Sep 29 '23 23:09 github-actions[bot]

Hi, when building a RN app, import and export are handled by the bundler (Metro), not by Hermes. The bundler combines all source files together into a single file, transforms the JS to implement import/export (among other things), and only then passes the result to Hermes.

I am moving this issue to React Native.

tmikov avatar Sep 29 '23 23:09 tmikov

Passing over to Metro (cc @robhogan @huntie)

cortinico avatar Oct 02 '23 21:10 cortinico

Facing the same issue. Because of this inline requires does not work, and entire project has to be parsed just to run app. After switching to named exports, problem solved itself. But logically there should be no difference

bajormar avatar Nov 30 '23 20:11 bajormar