title | description | canonical |
---|---|---|
Import from / Export to JS | Importing / exporting JS module content in ReScript | /docs/manual/latest/import-from-export-to-js |
You've seen how ReScript's idiomatic Import & Export works. This section describes how we work with importing stuff from JavaScript and exporting stuff for JavaScript consumption.
Note: due to JS ecosystem's module compatibility issues, our advice of keeping your ReScript file's compiled JS output open in a tab applies here more than ever, as you don't want to subtly output the wrong JS module import/export code, on top of having to deal with Babel/Webpack/Jest/Node's CommonJS<->ES6 compatibility shims.
In short: make sure your bindings below output what you'd have manually written in JS.
We support 2 JavaScript import/export formats:
- CommonJS:
require('myFile')
andmodule.export = ...
. - ES6 modules:
import * from 'MyReScriptFile'
andexport let ...
.
The format is configurable in bsb.
Use the module
external:
<CodeTab labels={["ReScript", "JS Output (CommonJS)", "JS Output (ES6)"]}>
// Import nodejs' path.dirname @module("path") externaldirname: string=>string="dirname"letroot=dirname("/User/github") // returns "User"
varPath=require("path");varroot=Path.dirname("/User/github");
import*asPathfrom"path";varroot=Path.dirname("/User/github");
Here's what the external
does:
@module("path")
: pass the name of the JS module; in this case,"path"
. The string can be anything:"./src/myJsFile"
,"@myNpmNamespace/myLib"
, etc.external
: the general keyword for declaring a value that exists on the JS side.dirname
: the binding name you'll use on the ReScript side.string => string
: the type signature ofdirname
. Mandatory forexternal
s.= "dirname"
: the name of the variable inside thepath
JS module. There's repetition in writing the first and seconddirname
, because sometime the binding name you want to use on the ReScript side is different than the variable name the JS module exported.
By omitting the string argument to module
, you bind to the whole JS module:
<CodeTab labels={["ReScript", "JS Output (CommonJS)", "JS Output (ES6)"]}>
@moduleexternalleftPad: string=>int=>string="./leftPad"letpaddedResult=leftPad("hi", 5)
varLeftPad=require("./leftPad");varpaddedResult=LeftPad("hi",5);
import*asLeftPadfrom"./leftPad";varpaddedResult=LeftPad("hi",5);
Depending on whether you're compiling ReScript to CommonJS or ES6 module, this feature will generate subtly different code. Please check both output tabs to see the difference. The ES6 output here would be wrong!
Use the value "default"
on the right hand side:
<CodeTab labels={["ReScript", "JS Output (ES6)"]}>
@module("./student") externalstudentName: string="default"Js.log(studentName)
importStudentfrom"./student";varstudentName=Student;
As mentioned in ReScript's idiomatic Import & Export, every let binding and module is exported by default to other ReScript modules (unless you use a .resi
interface file). If you open up the compiled JS file, you'll see that these values can also directly be used by a JavaScript file too.
If your JS project uses ES6 modules, you're likely exporting & importing some default values:
// student.jsexportdefaultname="Al";
// teacher.jsimportstudentNamefrom'student.js';
A JavaScript default export is really just syntax sugar for a named export implicitly called default
(now you know!). So to export a default value from ReScript, you can just do:
<CodeTab labels={["ReScript", "JS Output (CommonJS)", "JS Output (ES6)"]}>
// ReScriptStudent.resletdefault="Bob"
var$$default="Bob";exports.$$default=$$default;exports.default=$$default;// informal transpiler-compatible marker of a default export compiled from ES6exports.__esModule=true;
var$$default="Bob";export{$$default,$$defaultasdefault,}
You can then import this default export as usual on the JS side:
// teacher2.jsimportstudentNamefrom'ReScriptStudent.js';
If your JavaScript's ES6 default import is transpiled by Babel/Webpack/Jest into CommonJS require
s, we've taken care of that too! See the CommonJS output tab for __esModule
.