Skip to content

Dynamic import ergonomics #5593

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

Closed
nkrkv opened this issue Jul 29, 2022 · 9 comments
Closed

Dynamic import ergonomics #5593

nkrkv opened this issue Jul 29, 2022 · 9 comments
Milestone

Comments

@nkrkv
Copy link
Contributor

nkrkv commented Jul 29, 2022

This is a follow up of the forum post

When it comes to dynamic import of modules in ReScript, it looks verbose. For example, given a React component, we can make its dynamic counterpart like this:

module DynamicWidget = {
  let makeProps = () => Js.Obj.empty() // <- 1
  let make = {
    // The example uses NextJS but it does not matter much
    // The focus is on `import`
    open Next.Dynamic
    dynamic(
      () =>
        import_("./Widgets/Widget.bs.js") // <- 2
        ->PromiseX.map(x => x["make"]), // <- 3
      options(~loading=() => <MaterialUi.CircularProgress />, ~ssr=false, ()),
    )
  }
}

// Later use <DynamicWidget /> as a regular component

Three issues inconveniences:

  1. Since we don’t use @react.component here, we have to define makeProps for myself. It should go away when JSX V4 will be released.
  2. Here we should know the exact path to .bs.js. Perhaps some magic possible to just mention a module name and the path comes out automatically
  3. We have to tweak the import result since ReScript components don’t provide the default export (aren’t they?).

The dynamic import problem is not specific to JSX / React components only. import might be used for regular modules as well. I wonder if ReScript can make dynamic imports a little more ergonomic.

@cristianoc cristianoc added this to the v10.1 milestone Jul 29, 2022
@nkrkv
Copy link
Contributor Author

nkrkv commented Jul 29, 2022

One thought about how could it look like. What if ReScript introduce an @import annotation that can be used like this:

let modulePromise = @import ModuleName.functionName
// or later, with syntax support
let modulePromise = import(ModuleName.functionName)

Given that, along with JSX V4, the original example will be:

module DynamicWidget = {
  open Next.Dynamic
  let make = dynamic(() => import(Widget.make), options(~ssr=false, ()))
}

// Then

<Suspense fallback={...}>
  <DynamicWidget />
</Suspense>

@mununki
Copy link
Member

mununki commented Jul 30, 2022

AFAIK, the import() should have a string arg which is the js module path. The example intends @import or import to transform the Widget.make to the component's path as a string. Is it your idea?
IMHO, the pain points are no. 1 and no.3 which can be resolved by compiler. No. 2 (should know the component's path) seems inevitable to me.

EDIT: No 2. seems possible to be transformed to the component's path. It is not very different from the normal import in output js.

@mununki
Copy link
Member

mununki commented Jul 30, 2022

module DynamicWidget = {
  open Next.Dynamic
  @react.component(dynamic)
  let make = dynamic(() => import(Widget.make), { ssr: false })
}

// generated to

module DynamicWidget = {
  open Next.Dynamic
  type props = Widget.props // <-- 1
  let make = dynamic(() => import(Widget.make), { ssr: false })
}

// output in js
var DynamicWidget = dynamic(() => import("./Widgets/Widget.bs.js"), { ssr: false }) // <-- 2

1 can be processed by jsx ppx. but 2 needs to be processed in js emitter, I guess. Widget.bs.js needs export default additionally in order to resolve 3.

@zth
Copy link
Collaborator

zth commented Jul 30, 2022

I'm shortly making a RFC post on the forums so we can start discussing a spec for dynamic imports in ReScript, and figure out all of the use cases we want to support, and how to support them best. Just a heads up 😃

@zth
Copy link
Collaborator

zth commented Jul 30, 2022

Forum RFC posted here: https://forum.rescript-lang.org/t/rfc-dynamic-imports-in-rescript/3605

@nkrkv
Copy link
Contributor Author

nkrkv commented Jul 31, 2022

The example intends @import or import to transform the Widget.make to the component's path as a string. Is it your idea?

Almost. I mean whenever I use import and provide Foo.Bar.Baz.qux as its argument, where Foo.Bar is a file-module Foo__Bar.res and Baz is a nested module, it would be great if the compiler infers the module path (say, ../../Components/Foo__Bar.bs.js) and then extracts the rest from that module as a part of an automatic Promise.then (e.g., m => m.Baz.qux)

@cristianoc
Copy link
Collaborator

@mattdamon108 anything in here that should still affect the design of PPX V4?
If not, moving to milestone 10.2.

@cristianoc cristianoc modified the milestones: v10.1, v10.2 Sep 8, 2022
@mununki
Copy link
Member

mununki commented Sep 8, 2022

Thank you for asking. I don't think this feature should affect the PPX V4 for now. I agree to move to milestone 10.2.

@cristianoc
Copy link
Collaborator

The dynamic import PR subsumes this.

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

No branches or pull requests

4 participants