ES6:条件付きおよび動的インポートステートメント


86

条件付き

以下のような条件付きインポートステートメントを持つことは可能ですか?

if (foo === bar) {
    import Baz from './Baz';
}

上記を試しましたが、コンパイル時に(Babelから)次のエラーが発生します。

'import' and 'export' may only appear at the top level

動的

以下のような動的インポートステートメントを持つことは可能ですか?

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        import Baz from `./${foo}`;
    }
}

上記は、コンパイル中にBabelから同じエラーを受け取ります。

これは可能ですか、それとも私が欠けているものがありますか?

推論

私がこれを行おうとしている理由は、私が多くの「ページ」に対して多くのインポートを持っており、それらが同様のパターンに従っているためです。動的なforループを使用してこれらのファイルをインポートすることにより、コードベースをクリーンアップしたいと思います。

これが不可能な場合、ES6で多数のインポートを処理するためのより良い方法はありますか?


1
そのような場合、継承は使用できませんか?super特定の呼び出しに使用します。
ジャイ2016年

私はすでに継承を使用していますが、これらの「ページ」には「ページ」固有のロジックが含まれています。私はすべて拡張する基本的な「ページ」クラスを持っていますが、これは私が持っている膨大な数のインポートをクリーンアップするのに十分ではありません。
enijar 2016年

1
@zerkms:それらはブロックから引き上げられていません-それらは構文エラーです。
ベルギ2016年

node.jsES6変数のインポート名が重複している可能性がありますか?
ベルギ2016年

回答:


54

現在、ECMAで動的インポートの提案があります。これはステージ2にあります。これはbabel-presetとしても利用できます。

以下は、ケースに応じて条件付きレンダリングを行う方法です。

if (foo === bar) {
    import('./Baz')
    .then((Baz) => {
       console.log(Baz.Baz);
    });
}

これは基本的に約束を返します。約束の解決には、モジュールが必要です。この提案には、複数の動的インポート、デフォルトインポート、jsファイルインポートなども含まれています動的インポートの詳細については、こちらをご覧ください


3
この。動的インポートがその方法です。モジュールではなくpromiseを提供することを除いて、require()と同じように機能します。
スーパールミナリー2018

25

imports静的分析を目的としているため、依存関係を動的に解決することはできません。ただし、requireここでは次のようなものを使用できます。

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        const Baz = require(foo).Baz;
    }
}

8
「インポートは静的分析を目的としているため。」---このステートメントはあいまいです。importは、分析用ではなく、インポートするように設計されています。
zerkms 2016年

13
@ zerkms-importステートメントは静的分析に適していることを意味していると思います-条件付きではないため、ツールは依存関係ツリーをより簡単に分析できます。
ジョー・クレイ

4
「foo」、「baz」、「bar」では理解しにくい-実際の例はどうですか?
TetraDev 2016年

1
これはもはや真実ではありません。動的インポートが重要になりました。こちらをご覧ください:stackoverflow.com/a/46543949/687677
スーパールミナリー2018

7

この質問はGoogleによって上位にランク付けされているため、古い回答が投稿されてから状況が変わったことを指摘する価値があります。

MDNには、動的インポートの下に次のエントリがあります。

importキーワードは、モジュールを動的にインポートする関数として呼び出すことができます。このように使用すると、promiseが返されます。

import('/modules/my-module.js')
  .then((module) => {
    // Do something with the module.
  });

// This form also supports the await keyword.
let module = await import('/modules/my-module.js');

このテーマに関する有用な記事はMediumにあります。


2

2016年以来、JavaScriptの世界では多くのことが経過しているので、このトピックに関する最新の情報を提供する時が来たと思います。現在、動的インポートノードブラウザーの両方現実的です(IEを気にしない場合は当然、気にする場合は@ babel / plugin-syntax-dynamic-importを使用)。

したがって、something.js2つの名前付きエクスポートと1つのデフォルトエクスポートを持つサンプルモジュールについて考えてみます。

export const hi = (name) => console.log(`Hi, ${name}!`)
export const bye = (name) => console.log(`Bye, ${name}!`)
export default () => console.log('Hello World!')

import()構文を使用して、条件付きで簡単かつクリーンにロードできます。

if (somethingIsTrue) {
  import('./something.js').then((module) => {
    // Use the module the way you want, as:
    module.hi('Erick') // Named export
    module.bye('Erick') // Named export
    module.default() // Default export
  })
}

ただし、戻り値は、Promiseであるため、async/await構文糖も可能です。

async imAsyncFunction () {
  if (somethingIsTrue) {
    const module = await import('./something.js')
    module.hi('Erick')
  }
}

ここで、オブジェクト破壊割り当てとともに可能性について考えてください。たとえば、後で使用するために、名前付きエクスポートの1つだけをメモリに簡単に配置できます。

const { bye } = await import('./something.js')
bye('Erick')

または、これらの名前付きエクスポートの1つを取得して、名前を別の名前に変更します。

const { hi: hello } = await import('./something.js')
hello('Erick')

または、デフォルトのエクスポートされた関数の名前をより意味のある名前に変更することもできます。

const { default: helloWorld } = await import('./something.js')
helloWorld()

最後の(しかし少なくとも)注意: import()関数呼び出しのように見えるかもしれませんが、そうではありませんFunction。これは、かっこを使用するだけの特別な構文です(で発生するのと同様super())。したがってimport、変数に割り当てたり、/Functionなどのプロトタイプのものを使用したりすることはできません。callapply


1

Requireは同期呼び出しであるため、問題を解決しません。いくつかのオプションがあり、それらはすべて含まれています

  1. 必要なモジュールを要求する
  2. モジュールを返す約束を待っています

ECMAスクリプトでは、SystemJSを使用した遅延読み込みモジュールがサポートされています。もちろん、これはすべてのブラウザーでサポートされているわけではないため、当面の間は、JSPMまたはSystemJSシムを使用できます。

https://github.com/ModuleLoader/es6-module-loader

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.