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

Support dynamic import #2765

Closed
wegry opened this issue Apr 21, 2018 · 11 comments
Closed

Support dynamic import #2765

wegry opened this issue Apr 21, 2018 · 11 comments

Comments

@wegry
Copy link
Contributor

wegry commented Apr 21, 2018

What version of OCaml are you using?
This is using bs-platform@3.0.

It would be nice if bucklescript supported code splitting via dynamic imports. Even though dynamic import is stage 3, Webpack has supported a version of it for quite some time code splitting.

/* Foo.re */
let x = 5;

/* Importer.re */
import(Foo /* maybe just a relative path? */) 
|> Js.Promise.then_(/* hand waving */);

would generate the following code

import ('./Foo.js').then(foo => foo.x);
@xtuc
Copy link

xtuc commented Apr 22, 2018

If you have a webpack loader for buckelscript you can just compile it down to the JavaScript import() and Webpack will handle the compilation.

@kennetpostigo
Copy link

kennetpostigo commented Apr 23, 2018

@xtuc this is not ideal. Not everyone uses webpack, nor should they be forced to if they are using bucklescript. I think this is more of, "Please support this within bucklescript platform itself" Just like bucklescript can support outputting ES Modules and CommonJS.

@gilbert
Copy link

gilbert commented May 8, 2018

import(Foo /* maybe just a relative path? */)

Supporting dynamic import like this might be tricky. In a browser environment, I don't know how BuckleScript would know what path to render, as it doesn't know the asset urls your server responds to. Also, what happens when you dynamically load an npm module?.

My personal feature wish is for BuckleScript to support import : string => Js.Promise.t(???) where we can, somehow, typecast the ??? to a module of our choice.

@bloodyowl
Copy link
Collaborator

right now I think things could unlock pretty easily:

/* X.re */
let x = 24;
/* App.re */
module type XT = {
  include (module type of {
             include X;
           });
};

/* the external is pretty stupid but it's just for demonstration purposes */
[@bs.val] external import : string => Js.Promise.t((module XT)) = "";

import("./X.bs")
|> Js.Promise.then_((res: (module XT)) => {
     module Y = (val res);
     Js.log(Y.x);
     Js.Promise.resolve();
   });

outputs

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


import("./X").then((function (res) {
        console.log(res[/* x */0]);
        return Promise.resolve(/* () */0);
      }));

/*  Not a pure module */

It'd only require BuckleScript to understand that in case X is a file, accessing its exports (here x) is through importedX##x and not importedX[0]

@cortopy
Copy link

cortopy commented Aug 19, 2018

Bumped into this https://github.com/kMeillet/bs-dynamic-import

@cortopy
Copy link

cortopy commented Aug 19, 2018

and this (recently updated) https://github.com/thangngoc89/reason-loadable

@outkine
Copy link

outkine commented Dec 4, 2018

My use case is more simple - I just need to import a json dynamically using webpack, but because [%%bs.raw] doesn't support dynamic strings, I can't follow the advice presented in the bsb docs. Is there a different way?

@wegry
Copy link
Contributor Author

wegry commented Dec 4, 2018

@outkine Webpack's dynamic import can't accept arbitrary strings at runtime either. It only works with hard-coded strings.

@yawaramin
Copy link
Contributor

yawaramin commented Jan 17, 2019

Here's a hacky workaround that relies on BuckleScript's nice feature of not mangling names.

/** Dataloader.re - just a binding to Facebook's Dataloader for demonstration purposes */

/** The type of the dynamically-imported module. */
type dynamic;

/** The [Dataloader] type. */
type t('a, 'b);

/** [import()] generates a dynamic import to [dataloader].
    {i PLEASE ENSURE} you use it like: {[
Dataloader.import() |> Js.Promise.then_(_dataloader => ...)
    ]}

    The [_dataloader] is especially important because it generates code
    that works with the rest of the below externals. */
[@bs.val] external import: (
  [@bs.as {json|"dataloader"|json}] _,
  unit
) => Js.Promise.t(dynamic) = "import";

type batchFn('a, 'b) = (. array('a)) => Js.Promise.t(array('b));
[@bs.new] external make: batchFn('a, 'b) => t('a, 'b) = "_dataloader.Dataloader";

/* Use.re */

let loader: Js.Promise.t(Dataloader.t(int, int)) = Dataloader.import()
  |> Js.Promise.then_(_dataloader => /* [_dataloader] naming is important here */
    Js.Promise.resolve(Dataloader.make((. array) =>
      Js.Promise.resolve(array)))
  );

This generates the output:

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


var loader = import(("dataloader")).then((function (_dataloader) {
        return Promise.resolve(new _dataloader.Dataloader((function (array) {
                          return Promise.resolve(array);
                        })));
      }));

exports.loader = loader;
/* loader Not a pure module */

@BlueHotDog
Copy link

@bobzhang maybe close this issue and consolidate discussion to:
#3919

@wegry
Copy link
Contributor Author

wegry commented Jun 16, 2022

Closing as I think #3919 probably supersedes this. I've been out of the Reason/Rescript game for quite some time now.

@wegry wegry closed this as completed Jun 16, 2022
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

No branches or pull requests

9 participants