Skip to content

Instantly share code, notes, and snippets.

@uupaa uupaa/2017_09_11.md
Last active Sep 12, 2017

Embed
What would you like to do?
Module import/export in JavaScript

Module import/export in JavaScript

import 構文は ES6 から言語仕様(ES Modules, ESM)に盛り込まれました。 モジュールの静的なロードが可能になりましたが、動的なロードはサポートされませんでした。

// static import

import { Foo, Bar } from "./path/to/module.js";

モジュールの動的なロードを実現するための追加仕様が dynamic import expression です。こちらは次期JavaScriptの仕様を検討する ESNext という枠組みの中で審議されています。 function like import ( import() )と表記される事もあります。

// dynamic import

let module = "./path/to/module.js";
import(`${module}`).then((Foo, Bar) => {
  console.log(`${module} loaded`);
});

import() は Promise を返す構造として定義されており、ES7 の async/await 構文と組み合わせて利用できます。

// async/await

async function getValue() {
  return await 42;
}
getValue().then(value => {
  console.log(value); // -> 42
});

impl

import, import() と、async/await の実装状況です (2017/09/11)

import { ... } from "..." import(...).then(...) async / await
Sync/Async Sync ASync ASync
ES ES 6 / ES Modules ESNext ES 7
Chrome 61 in dev 55
Safari 10.1 (iOS 10.3) TP 39 10.1 (iOS 10.3)
Firefox 52 (flag) 52
Edge 15 (flag) 15
Node 8.3

dynamic import in Safari

Safari TP 39 で実際に動作を確認することができます。

<!-- index.html -->
<script type="module" src="dynamic_import.js"></script>
// module.js
export default class DefaultClass { }
export class NiceClass { }
export function niceFunction() { }
export let value = 42;
// dynamic_import.js

// case 1. 単一の値(value) を import する使い方
{
  import('./module.js').then(({ value }) => {
    console.log(value);             // -> 42
  }).catch(err => {
    console.log(err.message);
  });
}

// case 2. export default も含めた、複数の member を import する使い方
{
  import(`./module.js`).then(({
    default: DefaultClass,
    NiceClass,
    niceFunction,
    value
  }) => {
    console.log(DefaultClass.name); // -> "DefaultClass"
    console.log(NiceClass.name);    // -> "NiceClass"
    console.log(niceFunction.name); // -> "niceFunction"
    console.log(value);             // -> 42
  }).catch(err => {
    console.log(err.message);
  });
}

// case 3. async / await を併用し、複数回に分けて import する使い方
// Promise.then を隠蔽している
{
  (async () => {
    const modulePath = `./module.js`;
    const { default: DefaultClass, NiceClass } = await import(`${modulePath}`);
    const { niceFunction, value } = await import(`${modulePath}`);

    console.log(DefaultClass.name); // -> "DefaultClass"
    console.log(NiceClass.name);    // -> "NiceClass"
    console.log(niceFunction.name); // -> "niceFunction"
    console.log(value);             // -> 42
  })();


  // エラーハンドリングを行う場合はこのように記述します
  (async () => {
    const { default: DefaultClass, NiceClass } = await import(`${modulePath}`);
  })().catch(err => {
    console.log(err.message);
  });
}

dynamic import in Chrome

Chrome でもフラグ付きで実装が進んでいます

  • --enable-module-scripts-dynamic-import
  • chrome://flags/#enable-module-scripts-dynamic-import

static import in node.js

Node.js では require 構文が長年利用されてきた関係で、import へのスムーズな移行が難しい状況にあります。 2018/Q1 頃までになんらかの方向性を提案する予定とありますが、現在有力視されているのは、 従来の CommonJS(requre/module.exports)スタイルのコードの拡張子を *.js とし、 ES Modules スタイルで書かれたコードの拡張子を *.mjs にする方法です。

https://medium.com/the-node-js-collection/an-update-on-es6-modules-in-node-js-42c958b890c

このmjs拡張子(マイケルジャクソン拡張子)は、npm に蓄積された資産的な都合から提案されているのですが、 どちらかと言うと否定的な反応が多く観測されており、どうなるか揺れているようです。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.