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

Document the importInterop option #2476

Merged
merged 2 commits into from Apr 29, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
121 changes: 99 additions & 22 deletions docs/plugin-transform-modules-commonjs.md
Expand Up @@ -4,6 +4,13 @@ title: @babel/plugin-transform-modules-commonjs
sidebar_label: Common JS
---

<details>
<summary>History</summary>
| Version | Changes |
| --- | --- |
| `v7.14.0` | Implemented the `importInterop` option |
</details>

> **NOTE**: This plugin is included in `@babel/preset-env` under the `modules` option

This plugin transforms ECMAScript modules to [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1). Note that only the _syntax_ of import/export statements (`import "./mod.js"`) and import expressions (`import('./mod.js')`) is transformed, as Babel is unaware of different resolution algorithms between implementations of ECMAScript modules and CommonJS.
Expand Down Expand Up @@ -68,6 +75,90 @@ require("@babel/core").transformSync("code", {

## Options

### `importInterop`

`"babel" | "node" | "none"`, or `(specifier: string) => "babel" | "node" | "none"`. Defaults to `"babel"`.

CommonJS modules and ECMAScript modules are not fully compatible. However, compilers, bundlers and JavaScript
nicolo-ribaudo marked this conversation as resolved.
Show resolved Hide resolved
runtimes developed different strategies to make them work together as well as possible.

This option specify which interop strategy Babel should use. When it's a function, Babel calls this function
nicolo-ribaudo marked this conversation as resolved.
Show resolved Hide resolved
passing the import specifier (for example, `@babel/core` in `import { transform } from "@babel/core"`), and the
function should return the interop to use for that specific import.

#### `"babel"`

When using exports with babel a non-enumerable `__esModule` property is exported. This property is then used to determine if the import _is_ the default export or if it _contains_ the default export.
nicolo-ribaudo marked this conversation as resolved.
Show resolved Hide resolved

```javascript
import foo from "foo";
import { bar } from "bar";
foo;
bar;

// Is compiled to ...

"use strict";

function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}

var _foo = _interopRequireDefault(require("foo"));
var _bar = require("bar");

_foo.default;
_bar.bar;
```

When this import interop is used, if both the imported and the importer module are compiled with Babel they behave as if none of them was copiled.
nicolo-ribaudo marked this conversation as resolved.
Show resolved Hide resolved

This is the default behavior.

#### `"node"`

When importing CommonJS files (either directly written in CommonJS, or generated with a compiler) Node.js always binds the `default` export to the value of `module.exports`.

```javascript
import foo from "foo";
import { bar } from "bar";
foo;
bar;

// Is compiled to ...

"use strict";

var _foo = require("foo");
var _bar = require("bar");

_foo;
_bar.bar;
```

This is not exactly the same as what Node.js does since Babel allows accessing any property of `module.exports` as a named export, while Node.js only allows importing _statically analyzable_ properties of `module.exports`. However, any import working in Node.js will also work when compiled with Babel using `importInterop: "node"`.
nicolo-ribaudo marked this conversation as resolved.
Show resolved Hide resolved

#### `"none"`

If you know that the imported file has been transformed with a compiler that stores the `default` export on `exports.default` (such as Babel), you can safely omit the `_interopRequireDefault` helper.

```javascript
import foo from "foo";
import { bar } from "bar";
foo;
bar;

// Is compiled to ...

"use strict";

var _foo = require("foo");
var _bar = require("bar");

_foo.default;
_bar.bar;
```

### `loose`

`boolean`, defaults to `false`.
Expand Down Expand Up @@ -110,28 +201,6 @@ Object.defineProperty(exports, "__esModule", {
In order to prevent the `__esModule` property from being exported, you can set
the `strict` option to `true`.

### `noInterop`

`boolean`, defaults to `false`

By default, when using exports with babel a non-enumerable `__esModule` property
is exported. This property is then used to determine if the import _is_ the default
export or if it _contains_ the default export.

```javascript
"use strict";

var _foo = _interopRequireDefault(require("foo"));

function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
```

In cases where the auto-unwrapping of `default` is not needed, you can set the
`noInterop` option to `true` to avoid the usage of the `interopRequireDefault`
helper (shown in inline form above).

### `lazy`

`boolean`, `Array<string>`, or `(string) => boolean`, defaults to `false`
Expand Down Expand Up @@ -167,3 +236,11 @@ The two cases where imports can never be lazy are:
way to know what names need to be exported.

> You can read more about configuring plugin options [here](https://babeljs.io/docs/en/plugins#plugin-options)

### `noInterop`

`boolean`, defaults to `false`

> ⚠️ **Deptecated**: Use the `importInterop` option instead.
nicolo-ribaudo marked this conversation as resolved.
Show resolved Hide resolved

When set to `true`, this option has the same behavior as setting `importInterop: "none"`.