Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unused static import emitted in addition to dynamic import #6223

Closed
cknitt opened this issue Apr 28, 2023 · 9 comments · Fixed by #6232
Closed

Unused static import emitted in addition to dynamic import #6223

cknitt opened this issue Apr 28, 2023 · 9 comments · Fixed by #6232
Assignees
Milestone

Comments

@cknitt
Copy link
Member

cknitt commented Apr 28, 2023

Consider the following modules:

A.res:

// This triggers the issue
let test = <div />

@react.component
let make = () => React.null

B.res:

let test = () => Js.import(A.make)

B.res compiles to the following B.bs.mjs with an unused static import of A at the top of the file:

// Generated by ReScript, PLEASE EDIT WITH CARE

import * as A from "./A.bs.mjs";

function test() {
  return import("./A.bs.mjs").then(function (m) {
              return m.make;
            });
}

export {
  test ,
}
/* A Not a pure module */

The unused static import is only emitted when the line let test = <div /> is present in A.res.

@cknitt cknitt added this to the v11.0 milestone Apr 28, 2023
@mununki
Copy link
Member

mununki commented Apr 28, 2023

Super catch! Thanks! I'll look into it.

@mununki
Copy link
Member

mununki commented Apr 28, 2023

I can reproduce and confirm only JSX expression triggers the issue.

@cristianoc
Copy link
Collaborator

cristianoc commented Apr 29, 2023

I'm not sure how much this has to do with JSX, which might be a red herring.
How about trying to desugar and simplify the example, in a way that does not use JSX.
E.g. what if "the function is used" is the trigger. Or "the function is defined twice" or something.

@cristianoc
Copy link
Collaborator

There we go: no JSX.

A.res:

let make = () => React.null

// This triggers the issue
let test = React.null

B.res:

let test = () => Js.import(A.make)

@mununki
Copy link
Member

mununki commented Apr 29, 2023

I grabbed some time to look and found that this is related to whether the imported module is pure or having side-effects.
This issue is triggered if the imported module has side-effect. For example, Array.map, assert false expressions trigger the issue.
I'm going to look into the implementation of deciding whether module has side effects and then removing the dynamic imported module from it.

@cristianoc
Copy link
Collaborator

Exactly. Whether the dynamically imported module has side effects or not, should not matter.

@mununki
Copy link
Member

mununki commented May 1, 2023

@cknitt Can you try to test with fix? And let me know any time to need to discuss about React.lazy implementation. It would be great to have for rescript-react users.

@cknitt
Copy link
Member Author

cknitt commented May 1, 2023

@mununki Thanks a lot for your work! Will test tomorrow.

@cknitt
Copy link
Member Author

cknitt commented May 2, 2023

@mununki I can confirm that dynamic loading / React.lazy works fine for me now like this even if DynamicallyImportedComponent is impure:

type reactModule<'a> = {default: React.component<'a>}

@module("react")
external lazy_: (unit => promise<reactModule<'a>>) => React.component<'a> = "lazy"

let lazy_ = factory => lazy_(async () => {default: await factory()})

module DynamicallyImportedComponent = {
  let make = lazy_(() => Js.import(DynamicallyImportedComponent.make))
}

(+ wrapping in React.Suspense where it is used)

Will look into integrating this in @rescript/react.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants