Node.js の開発版で ES モジュールローダーを試す



## 概要
2017年9月8日の Node.js 開発版から ES モジュールローダーを試すことができるようになりました。試験的な機能なので、スクリプトの実行時に `--experimental-modules` フラグを指定する必要があります。

## 公式マニュアル

Github の `node/doc/api/esm.md` を[ご参照](https://github.com/nodejs/node/blob/master/doc/api/esm.md)ください。

## NVS による開発版のインストール

開発版を手軽に試すには NVS (Node Version Swither) が手軽です。

```bash
nvs add nightly
nvs use nightly
```

正式な最新バージョンを導入するには次のコマンドを実行します。

```bash
nvs add latest
nvs use latest
```

## モジュールをつくる

ES モジュールをつくってみましょう。拡張子を `.mjs` にする必要があります。

```js:hello.mjs
const msg = "hello";

function hello() {
  console.log(msg);
}

export { msg, hello };
```

ES モジュールを読み込んで、実行するスクリプトの拡張子も `.mjs` にする必要があります。

```js:main.mjs
import { msg, hello } from "./hello";

console.log(msg);
hello();
```

## 実行

スクリプトを実行してみましょう。

```bash
node --experimental-modules main.mjs

(node:49617) ExperimentalWarning: The ESM module loader is experimental.
hello
hello
```

実行するスクリプトの拡張子が `.js` の場合、次のようなエラーメッセージが表示されます。

```bash
node --experimental-modules main.js
/Users/masakielastic/test/esm-project/main.js:1
(function (exports, require, module, __filename, __dirname) { import { msg, hello } from "./hello";
                                                              ^^^^^^

SyntaxError: Unexpected token import
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:564:28)
    at Object.Module._extensions..js (module.js:611:10)
    at Module.load (module.js:521:32)
    at tryModuleLoad (module.js:484:12)
    at Function.Module._load (module.js:476:3)
    at Function.Module.runMain (module.js:641:10)
    at startup (bootstrap_node.js:201:16)
    at bootstrap_node.js:626:3
```

読み込もうとするモジュールの拡張子が　`.js` の場合、次のようなエラーメッセージが表示されます。

```bash
(node:49783) ExperimentalWarning: The ESM module loader is experimental.
SyntaxError: The requested module does not provide an export named 'msg'
    at checkComplete (internal/loader/ModuleJob.js:86:27)
    at moduleJob.linked.then (internal/loader/ModuleJob.js:69:11)
    at <anonymous>
```

## 標準モジュールを読み込む

`url` モジュールの `URLSearchParams` を試してみましょう。

```js:client.mjs
import url from "url";

const params = new url.URLSearchParams();
params.append("msg", "hello world");

console.log(params.toString());
// msg=hello+world
```

記事の執筆時点では次の書き方はエラーになります。

```js
import { URLSearchParams } from "url";

const params = new URLSearchParams();
console.log(params.toString());
// msg=hello+world
```

エラーメッセージは次のとおりです。

```bash
SyntaxError: The requested module does not provide an export named 'URLSearchParams'
    at checkComplete (internal/loader/ModuleJob.js:86:27)
    at moduleJob.linked.then (internal/loader/ModuleJob.js:69:11)
    at <anonymous>
```


## 開発環境における代替策

開発環境でモジュールローダーを手軽に試したい場合の代替案が複数あります。

### `@std/esm`

 Node v4 から　ESM を利用できるようにするツールです。スクリプトの実行時に `r` オプションで読み込みます。
 
```bash
node -r @std/esm main.mjs
```

yarn で導入するには次のコマンドを実行できます。

```bash
yarn add --dev @std/esm
```

### babel-node と babel-preset-env


`babel-preset-env` のおかげでトランスパイルするコードの量を最小限に抑えることができます。


```js:package.json
{
  "babel": {
    "presets": [
      ["env", {"targets": { "node": "current" }}]
    ]
  }
}
```

Yarn による導入は次のとおりです。

```bash
yarn add --dev babel-cli babel-preset-env
```

スクリプトの実行に `npx` を使うことができます。

```
npx babel-node client.mjs
```

トランスパイルされたコードを見たいのであれば、`babel` コマンドを使います。

```bash
npx babel client.mjs
```