ECMAScript では、モジュールを読み込むための仕組みとしてimport
文を定義している。
// sub.js export const foo = 1; export default 2; // main.js import value, {foo} from './sub.js'; console.log(value, foo); // 2 1
import
文は仕様上、トップレベルで書くことになっており、以下のような書き方はシンタックスエラーになる。
// main.js // SyntaxError: 'import' and 'export' may only appear at the top level const call = () => { import value, {foo} from './sub.js'; }; // SyntaxError: 'import' and 'export' may only appear at the top level if (true) { import value, {foo} from './sub.js'; }
そして、読み込まれるファイルは、読み込まれた瞬間に実行される。
そのため、以下のmain.js
を実行すると、sub
、main
、2
の順番に表示される。
// sub.js console.log('sub'); export const foo = 1; export default 2; // main.js import value from './sub.js'; console.log('main'); console.log(value);
ES2020 で追加される仕様のひとつであるimport()
は、これまでのimport
文と異なり、モジュールを動的に読み込む。
また、トップレベルでないと使えないという制約もない。
読み込みたいモジュールのパスを引数として渡すと、読み込んだモジュールをPromise
でラップして返す。
// sub.js export const foo = 1; export default 2; // main.js console.log(import('./sub.js') instanceof Promise); // true import('./sub.js').then(res => { console.log(res.default); // 2 console.log(res.foo); // 1 });
非同期処理なので、以下のmain.js
を実行すると先にmain
が表示され、その後にsub
が表示される。
// sub.js console.log('sub'); export const foo = 1; export default 2; // main.js import('./sub.js'); console.log('main');
関数のなかで使うこともできる。
// sub.js export const foo = 1; export default 2; // main.js const call = () => { return import('./sub.js').then(res => { return res.default; }); }; call().then(res => { console.log(res); // 2 });
フラグに応じて読み込むファイルを変える、ということも可能になる。
以下のコードでは、sub.js
はsomeFlag
がtruthy
のときにのみ読み込まれる。
// sub.js export default 'This is confidential information.'; // main.js (async () => { const someFlag = true; const message = someFlag ? await import('./sub.js').then(res => res.default) : 'please login'; console.log(message); // This is confidential information. })();