Let’s discuss how dynamic import can best be supported in ReScript. Before discussing a potential implementation, let’s try to find a definition for what a dynamic import is, what it means to ReScript, and then map out all of the use cases we want to support. This is a continuation of this GitHub issue: https://github.com/rescript-lang/rescript-compiler/issues/5593
Worth noting that dynamic imports are possible to do already in ReScript, but they need lots of manual and error prone plumbing and aren’t very safe.
What is a dynamic import?
import - JavaScript | MDN ← this is the general definition, and what we’ll want to compile to in the end. Essentially, it’s a function that takes a string pointing to a JS file containing ES modules. That function then returns a promise that resolves to the full file as an object with all exports from the file on it.
In TS, you do dynamic imports just like in JS, so import("./path/to/file.js")
. But TS can infer the type of the file you’re pointing to, which means that the import will be typed correctly. This leads to the experience being essentially:
const fileJs = await import("./some/file.js");
fileJs.someFunc();
What could dynamic import mean in ReScript?
What we want for dynamic imports in ReScript is probably a bit different to the JS/TS version. We don’t want to have to care about files and file names when we’re coding, since ReScript only have us caring about what modules are accessible in the current scope. So, ideally we focus on how to dynamically import a module, without needing to know the path of the generated file for that module.
Open ended question; What does this mean for file level modules vs nested modules? File level modules, as in “this file is a module”, is the only thing that’s going to map 1:1 to how JS does it - importing an entire file. But whether a module is at the file level or not isn’t necessarily anything you need to think about today when using ReScript.
Use cases
Here’s a non exhaustive list of use cases for dynamic imports. Please feel free to add to this thread so we cover as much ground as possible.
Dynamically importing a module
This is the standard use case, dynamically importing module X and then using exports from it. How it looks in JS:
const fileJs = await import("./some/file.js");
fileJs.someFunc();
React.lazy
This is a React specific API that expects to be fed a function that dynamically imports a module with a React component as the default export. It’s a bit tricky because we want to preserve the props type from the React component. How it looks in JS:
const MyLazyComponent = React.lazy(() => import("./some/MyComponent.js"));
<MyLazyComponent />
Discussion
Let’s start here and discuss what dynamic imports could mean in ReScript, and what we want to support. Eager to hear your thoughts and reflections.