ES6モジュールを条件付きでインポートするにはどうすればよいですか?


192

私は次のようなことをする必要があります:

if (condition) {
    import something from 'something';
}
// ...
if (something) {
    something.doStuff();
}

上記のコードはコンパイルされません。投げSyntaxError: ... 'import' and 'export' may only appear at the top levelます。

ここSystem.import示すように使ってみましたが、どこSystemから来たのかわかりません。受け入れられなかったES6の提案ですか?その記事からの「プログラムAPI」へのリンクは、非推奨のドキュメントページにダンプします


通常どおりインポートします。あなたのモジュールはそれを必要とします。
アンディ

条件に関係なくインポートしない理由は本当にわかりません。なんらかのオーバーヘッドがあるわけではありません。一部のシナリオではファイルが必要になるため、完全にスキップできる場合はありません。その場合は無条件でインポートしてください。
ありがとう

8
私の使用例:オプションの依存関係を簡単に設定できるようにしたい。depが不要な場合、ユーザーはそれをから削除しpackage.jsonます。私のgulpfileその後のチェックは、その依存性は、いくつかのビルド手順を実行する前に存在している場合。
ericsoco 2016

1
別の使用例:テスト目的。私が使用していますwebpackし、babeltranspile ES6にES5へ。webpack-rewire似たようなプロジェクトはここでは役に立ちません-github.com/jhnns/rewire-webpack/issues/12。テストを2倍に設定する、または問題のある依存関係を削除する1つの方法は、条件付きインポートです。
Amio.io 2016

3
+1。依存関係が機能する場合と機能しない場合がある複数の環境でモジュールを使用できることは、特にモジュールがブラウザでのみ機能する依存関係を参照する場合に重要です(たとえば、webpackを使用してスタイルシートをモジュールに変換し、関連するスタイルをDOMがインポートされたとき)ですが、モジュールはブラウザの外部で実行する必要もあります(ユニットテストなど)。
ジュール

回答:


142

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

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

if (condition) {
    import('something')
    .then((something) => {
       console.log(something.something);
    });
}

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


13
最後に、本当のES6の答えです!@thecodejackに感謝します。この記事によると、この記事の執筆時点では実際にはステージ3です。
ericsoco 2017年

5
またはあなたがちょうどあなたがdestructureできる輸出命名している場合:if (condition) { import('something') .then(({ somethingExported }) => { console.log(somethingExported); }); }
IVN

4
Firefoxで実行中npm run buildにもエラーが発生する:SyntaxError: ... 'import' and 'export' may only appear at the top level
18年

これはあなたのテストに失敗しました、誰かがアイデアを持っていますか?
stackjlei

1
この条件付き動的インポート関数には、「XからYをインポート」が持つ特定の要素のみをインポートするきめ細かな機能はありません。実際、細粒度の能力は、(前処理のバンドリングとは対照的に)動的ロードではさらに重要になる可能性があります
Craig Hicks

101

必要に応じて、requireを使用できます。これは、条件付きのrequireステートメントを持つ方法です。

let something = null;
let other = null;

if (condition) {
    something = require('something');
    other = require('something').other;
}
if (something && other) {
    something.doStuff();
    other.doOtherStuff();
}

1
ブロックスコープのconstを使用して何かや他の変数がdeclsredされたと思うので、2番目のif条件が何かをスローする場合は定義されません
Mohammed Essehemy

'var'を使用してブロックのスコープを完全に回避する代わりに、letを使用して2つの変数をブロックの外側で宣言する方が良いでしょう。
Vorcan

この場合、巻き上げは何かに影響しますか?メモリが機能している場合、これに近いパターンに従うと、巻き上げによってライブラリが予期せずインポートされてしまうという問題に遭遇しました。
トーマス

11
require()標準JavaScriptの一部ではないことを指摘する必要があります。これはNode.jsの組み込み関数なので、その環境でのみ役立ちます。OPはNode.jsでの作業を示しません。
Velojet

54

条件付きでインポートすることはできませんが、逆のことができます。条件付きで何かをエクスポートします。それはあなたのユースケースに依存するので、この回避策はあなたのためではないかもしれません。

できるよ:

api.js

import mockAPI from './mockAPI'
import realAPI from './realAPI'

const exportedAPI = shouldUseMock ? mockAPI : realAPI
export default exportedAPI

apiConsumer.js

import API from './api'
...

現在、ミックスパネルなどの分析ライブラリのモックに使用しています。現在、複数のビルドやフロントエンドを使用することはできないためです。最もエレガントではありませんが、動作します。ミックスパネルの場合は初期化が必要なので、環境に応じてあちこちにいくつかの「if」があります。


39
このソリューションは不要なモジュールをロードするため、最適なソリューションではないと思います。
ismailarilik 2017

5
回答で述べたように、これは回避策です。当時、解決策はありませんでした。ES6のインポートは動的ではありません。これは仕様によるものです。現在受け入れられている回答に記載されているES6動的インポート機能の提案は、それを行うことができます。JSは進化しています:)
Kev

9

答えは今のところできないということです。

http://exploringjs.com/es6/ch_modules.html#sec_module-loader-api

私の意図は可能な限り静的分析を可能にすることであり、条件付きでインポートされたモジュールはそれを壊します。また、言及する価値があります-私はBabelをSystem使用していますが、モジュールローダーAPIがES6標準になっていなかったため、Babelではサポートされていないと思います。


@FelixKlingはこれを独自の答えにし、喜んで受け入れます!
ericsoco 2016

4

require()ランタイムにいくつかのモジュールをインポートする方法であり、import文字列リテラルパスで使用される場合と同様に、静的分析の対象となります。これは、バンドルの依存関係を選択するために、バンドラーが必要とします。

const defaultOne = require('path/to/component').default;
const NamedOne = require('path/to/component').theName;

完全な静的分析をサポートする動的モジュール解決のために、最初にインデクサー(index.js)のインデックスモジュールとホストモジュールのインデクサーをインポートします。

// index.js
export { default as ModuleOne } from 'path/to/module/one';
export { default as ModuleTwo } from 'path/to/module/two';
export { SomeNamedModule } from 'path/to/named/module';

// host.js
import * as indexer from 'index';
const moduleName = 'ModuleOne';
const Module = require(indexer[moduleName]);

7
require()標準JavaScriptの一部ではないことを指摘する必要があります。これはNode.jsの組み込み関数なので、その環境でのみ役立ちます。OPはNode.jsでの作業を示しません。
Velojet

2

動的インポートWebpackモードを使用する場合の重要な違いeager

if (normalCondition) {
  // this will be included to bundle, whether you use it or not
  import(...);
}

if (process.env.SOMETHING === 'true') {
  // this will not be included to bundle, if SOMETHING is not 'true'
  import(...);
}

しかしimport、約束を返します。
ニューガイ

0

evalでそれを隠すことは私にとってはうまくいき、静的アナライザーからそれを隠しました...

if (typeof __CLI__ !== 'undefined') {
  eval("require('fs');")
}

3
なぜこの回答が反対投票されたのか誰かが説明できますか?実際の欠点はありますか、それとも邪悪なキーワード「eval」に対する自動的な否定的な反応でしたか?
ユーリゴー

3
hideous evalキーワードを使用するための自動反対投票。近づかないで。
Tormod Haugene

1
evalここ、@ TormodHaugeneの使用で実際に何が問題になっているのか説明できますか?
Adam Barnes

MDN evalは、使用すべきではない理由をかなり多くまとめています。一般に、を使用する必要があるeval場合は、おそらく間違っているため、代替策を検討するために一歩戻る必要があります。使用evalが正しいシナリオはおそらくいくつかありますが、それらの状況のいずれにも遭遇していない可能性が高いです。
Tormod Haugene

5
require()標準JavaScriptの一部ではないことを指摘する必要があります。これはNode.jsの組み込み関数なので、その環境でのみ役立ちます。OPはNode.jsでの作業を示しません。
Velojet

0

これは、すぐに呼び出される関数とrequireステートメントを使用して実現できました。

const something = (() => (
  condition ? require('something') : null
))();

if(something) {
  something.doStuff();
}

5
require()標準JavaScriptの一部ではないことを指摘する必要があります。これはNode.jsの組み込み関数なので、その環境でのみ役立ちます。OPはNode.jsでの作業を示しません。
Velojet

0

条件付きインポートは、3項とrequire()s でも実現できます。

const logger = DEBUG ? require('dev-logger') : require('logger');

この例は、ES Lintのglobal-requireドキュメントから取得されました。https//eslint.org/docs/rules/global-require


5
require()標準JavaScriptの一部ではないことを指摘する必要があります。これはNode.jsの組み込み関数なので、その環境でのみ役立ちます。OPはNode.jsでの作業を示しません。
Velojet


0

いいえ、できません!

ただし、その問題にぶつかったことで、コードの編成方法を再考する必要があります。

ES6モジュールの前は、require()構文を使用するCommonJSモジュールがありました。これらのモジュールは「動的」でした。つまり、コードの条件に基づいて新しいモジュールをインポートできました。-ソース:https : //bitsofco.de/what-is-tree-shaking/

彼らがES6以降のサポートを中止した理由の1つは、コンパイルが非常に困難または不可能であるという事実だと思います。

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