import 構文は ES6 から言語仕様(ES Modules, ESM)に盛り込まれました。 モジュールの静的なロードが可能になりましたが、動的なロードはサポートされませんでした。
// static import
import { Foo, Bar } from "./path/to/module.js";
- static import
モジュールの動的なロードを実現するための追加仕様が 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`);
});
- dynamic import
- spec: https://tc39.github.io/proposal-dynamic-import/
- article: http://2ality.com/2017/01/import-operator.html - Dr. Alex blog
import() は Promise を返す構造として定義されており、ES7 の async/await 構文と組み合わせて利用できます。
// async/await
async function getValue() {
return await 42;
}
getValue().then(value => {
console.log(value); // -> 42
});
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 |
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);
});
}
Chrome でもフラグ付きで実装が進んでいます
--enable-module-scripts-dynamic-import
chrome://flags/#enable-module-scripts-dynamic-import
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 に蓄積された資産的な都合から提案されているのですが、 どちらかと言うと否定的な反応が多く観測されており、どうなるか揺れているようです。