Skip to content

Commit 07f96b9

Browse files
authored
Much clearer js import/export explanations (rescript-lang#292)
Updated with 8.3.0 es6 import info
1 parent 7ad7249 commit 07f96b9

File tree

2 files changed

+54
-31
lines changed

2 files changed

+54
-31
lines changed

pages/docs/manual/latest/import-export.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ A ReScript project's file names need to be unique.
3131

3232
By default, every file's type declaration, binding and module is exported, aka publicly usable by another file. **This also means those values, once compiled into JS, are immediately usable by your JS code**.
3333

34-
To only export a few selected things, use an [interface file](module.md#signatures).
34+
To only export a few selected things, use a `.resi` [interface file](module.md#signatures).
3535

3636
## Work with JavaScript Import & Export
3737

pages/docs/manual/latest/import-from-export-to-js.mdx

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,26 @@ canonical: "/docs/manual/latest/import-from-export-to-js"
88

99
You've seen how ReScript's idiomatic [Import & Export](import-export.md) works. This section describes how we work with importing stuff from JavaScript and exporting stuff for JavaScript consumption.
1010

11+
**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.
12+
13+
In short: **make sure your bindings below output what you'd have manually written in JS**.
14+
15+
## Output Format
16+
17+
We support 2 JavaScript import/export formats:
18+
19+
- CommonJS: `require('myFile')` and `module.export = ...`.
20+
- ES6 modules: `import * from 'MyReScriptFile'` and `export let ...`.
21+
22+
The format is [configurable in bsb](build-configuration.md#package-specs).
23+
1124
## Import From JavaScript
1225

13-
### Import a JavaScript Module's Content
26+
### Import a JavaScript Module's Named Export
1427

1528
Use the `bs.module` [external](external.md):
1629

17-
<CodeTab labels={["ReScript", "JS Output"]}>
30+
<CodeTab labels={["ReScript", "JS Output (CommonJS)", "JS Output (ES6)"]}>
1831

1932
```res example
2033
// Import nodejs' path.dirname
@@ -25,22 +38,26 @@ let root = dirname("/User/github") // returns "User"
2538
var Path = require("path");
2639
var root = Path.dirname("/User/github");
2740
```
41+
```js
42+
import * as Path from "path";
43+
var root = Path.dirname("/User/github");
44+
```
2845

2946
</CodeTab>
3047

3148
Here's what the `external` does:
3249

33-
- `@bs.module("path")`: pass the name of the JS module as a string; in this case, `"path"`. The string can be anything: `"./src/myJsFile"`, `"@myNpmNamespace/myLib"`, etc.
50+
- `@bs.module("path")`: pass the name of the JS module; in this case, `"path"`. The string can be anything: `"./src/myJsFile"`, `"@myNpmNamespace/myLib"`, etc.
3451
- `external`: the general keyword for declaring a value that exists on the JS side.
3552
- `dirname`: the binding name you'll use on the ReScript side.
36-
- `string => string`: the type signature of `dirname`.
53+
- `string => string`: the type signature of `dirname`. Mandatory for `external`s.
3754
- `= "dirname"`: the name of the variable inside the `path` JS module. There's repetition in writing the first and second `dirname`, because sometime the binding name you want to use on the ReScript side is different than the variable name the JS module exported.
3855

39-
### Import a JavaScript Module Itself (CommonJS)
56+
### Import a JavaScript Module As a Single Value
4057

4158
By omitting the string argument to `bs.module`, you bind to the whole JS module:
4259

43-
<CodeTab labels={["ReScript", "JS Output"]}>
60+
<CodeTab labels={["ReScript", "JS Output (CommonJS)", "JS Output (ES6)"]}>
4461

4562
```res example
4663
@bs.module external leftPad: string => int => string = "./leftPad"
@@ -50,40 +67,41 @@ let paddedResult = leftPad("hi", 5)
5067
var LeftPad = require("./leftPad");
5168
var paddedResult = LeftPad("hi", 5);
5269
```
70+
```js
71+
import * as LeftPad from "./leftPad";
72+
var paddedResult = LeftPad("hi", 5);
73+
```
5374

5475
</CodeTab>
5576

56-
### Import a JavaScript Module Itself (ES6 Module Format)
77+
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!
78+
79+
### Import an ES6 Default Export (Since >= 8.3.0)
5780

58-
If your JS project is using ES6, you're likely using Babel to compile it to regular JavaScript. Babel's ES6 default export actually exports the default value under the name `default`. You'd bind to it like this:
81+
Use the value `"default"` on the right hand side:
5982

60-
<CodeTab labels={["ReScript", "JS Output"]}>
83+
<CodeTab labels={["ReScript", "JS Output (ES6)"]}>
6184

6285
```res example
6386
@bs.module("./student") external studentName: string = "default"
6487
Js.log(studentName)
6588
```
6689
```js
67-
var Student = require("./student");
68-
console.log(Student.default);
90+
import Student from "./student";
91+
var studentName = Student;
6992
```
7093

7194
</CodeTab>
7295

7396
## Export To JavaScript
7497

75-
As mentioned in ReScript's idiomatic [Import & Export](import-export.md), every let binding and module is exported by default to other ReScript modules. If you open up the compiled JS file, you'll see that these values can also directly be used by another _JavaScript_ file too.
76-
77-
We support 2 JS export formats:
98+
### Export a Named Value
7899

79-
- CommonJS (usable from JS as `require('myFile')`).
80-
- ES6 modules (usable from JS as `import * from 'myFile'`).
100+
As mentioned in ReScript's idiomatic [Import & Export](import-export.md), every let binding and module is exported by default to other ReScript modules (unless you use a `.resi` [interface file](module#signatures)). If you open up the compiled JS file, you'll see that these values can also directly be used by a _JavaScript_ file too.
81101

82-
The output format is [configurable in bsb](build-configuration.md#package-specs).
102+
### Export an ES6 Default Value
83103

84-
### Export an ES6 default value
85-
86-
If your JS project is using ES6 modules, you're likely exporting & importing some default values:
104+
If your JS project uses ES6 modules, you're likely exporting & importing some default values:
87105

88106
```js
89107
// student.js
@@ -95,33 +113,38 @@ export default name = "Al";
95113
import studentName from 'student.js';
96114
```
97115

98-
Technically, since a ReScript file maps to a module, there's no such thing as "default" export, only named ones. However, we've made an exception to support default module when you do the following:
116+
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:
99117

100-
<CodeTab labels={["ReScript", "JS Output"]}>
118+
<CodeTab labels={["ReScript", "JS Output (CommonJS)", "JS Output (ES6)"]}>
101119

102120
```res example
103-
/* FavoriteStudent.res */
121+
// ReScriptStudent.res
104122
let default = "Bob"
105123
```
106124
```js
107125
var $$default = "Bob";
108126

109127
exports.$$default = $$default;
110128
exports.default = $$default;
129+
// informal transpiler-compatible marker of a default export compiled from ES6
111130
exports.__esModule = true;
112131
```
132+
```js
133+
var $$default = "Bob";
134+
135+
export {
136+
$$default,
137+
$$default as default,
138+
}
139+
```
113140

114141
</CodeTab>
115142

116-
You can then require the default as normal JS side:
143+
You can then import this default export as usual on the JS side:
117144

118145
```js
119146
// teacher2.js
120-
import studentName from 'FavoriteStudent.js';
147+
import studentName from 'ReScriptStudent.js';
121148
```
122149

123-
**Note**: the above JS snippet _only_ works if you're using that ES6 import/export syntax in JS. If you're still using `require`, you'd need to do:
124-
125-
```js
126-
let studentName = require('FavoriteStudent').default;
127-
```
150+
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`.

0 commit comments

Comments
 (0)