rescript-compiler icon indicating copy to clipboard operation
rescript-compiler copied to clipboard

Dynamic import support

Open bobzhang opened this issue 4 years ago • 10 comments

type xx 

type 'a promise 

external import : 
  'a  -> 
  ('a -> unit) -> 
  unit promise = "bootload" [@@bs.val]
;;  
module type LIST = module type of List  
;;
let _ : _ promise =     
    import (module List :  LIST)(fun (module List) -> 
  Js.log (List.length [1;2]);
  ()
  )

Todo:

  • Have a way to delay the generated requires for List
  • See if we can mitigate the runtime cost
  • Check to see how to ensure invariants enforced by bootload, e.g, it can only load a global module?

bobzhang avatar Nov 02 '19 01:11 bobzhang

Is this regarding #2765 ?

yawaramin avatar Nov 02 '19 02:11 yawaramin

@yawaramin yes, except the proposal here is more type safe?

bobzhang avatar Nov 02 '19 02:11 bobzhang

@bobzhang your approach here made me think about this a bit more and now I think we can do dynamic imports with just bs.val and bs.as (treating import as just a normal function), here's an example:

(* foo.ml *)
let x = 0

(* import.ml *)
module type FOO = sig
  val x : int
end

external foo : (_ [@bs.as "./foo.bs"]) -> (module FOO) Js.Promise.t =
  "import" [@@bs.val]

let _ = foo |> Js.Promise.then_(fun (module Foo : FOO) ->
  Foo.x |> Js.log |> Js.Promise.resolve)

This generates:

// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';


import("./foo.bs").then((function (Foo) {
        return Promise.resolve((console.log(Foo.x), /* () */0));
      }));

/*  Not a pure module */

[EDIT: this is possible now thanks to the modules-as-objects change! On previous versions this would compile as Foo[/* x */ 0]]

yawaramin avatar Nov 02 '19 03:11 yawaramin

@bobzhang has there been progress on this? that'd be crucial for overall performance

bloodyowl avatar Nov 23 '19 10:11 bloodyowl

@bobzhang any update? :-)

sorenhoyer avatar Nov 05 '20 21:11 sorenhoyer

@yawaramin your solution works fine. Can we make it little more generic, so that it works for any module.

Something like below

module type DyImpConfig = {module type T;};

module Make = (Config: DyImpConfig) => {
  [@bs.val] external importRe: string => Js.Promise.t(module Config.T) = "import";
};

tejesh014 avatar Nov 12 '20 06:11 tejesh014

@tejesh014 sure, that makes sense. I'll write up an article about it on my blog when I get some time.

yawaramin avatar Nov 12 '20 14:11 yawaramin

I'm also interested in whether there has been any recent movement/plans here. 👀

zth avatar Nov 25 '20 18:11 zth

Also looking to this

BlueHotDog avatar Jan 19 '21 11:01 BlueHotDog

hey, any changes here?

BlueHotDog avatar Apr 02 '22 12:04 BlueHotDog

#5703

mununki avatar Apr 23 '23 16:04 mununki