web-dev-qa-db-ja.com

Webpack2-トップレベルの依存関係を分割するコード

最終編集

これのtl; dr解決は、それが不可能であるということです。以下の一番上の答えにはいくつかの良い情報がありますが。


contacts.jsからの以下のコードを検討してください。これは動的にロードされるモジュールであり、コードの他の場所でSystem.importを使用してオンデマンドでロードされます。

SharedUtil1が他のモジュールでも使用されており、それらも動的にSystem.importでロードされている場合、SharedUtility1除外これらのモジュールのすべてから、オンデマンドでのみ初回必要ですか?

System.importのトップレベルのSharedUtil1は、エクスポートがそれに依存しているため機能しません。エクスポートは、モジュールのコードのトップレベルにのみ配置でき、コールバックには配置できません。

これはWebpackで可能ですか?私はバージョン2.0.7ベータ版を使用しています。

import SharedUtil1 from '../../SharedUtilities/SharedUtility1';

class Contacts{
    constructor(data){
        this.data = data;
        this.sharedUtil1 = new SharedUtil1();
    }
}

export default Contacts;

更新1

バンドルローダー が私が望んでいたものだと思いましたが、非同期でロードが完了すると、インポートされたモジュールを、実際のモジュールに到達するためにコールバックで呼び出す別の関数に変換します。これは、コードに重大な変更を加えずにモジュールXを非同期的にロードすることはできないことを意味します。もちろん、最初に説明した問題に戻ったという事実は言うまでもなく、トップレベルのモジュールが今非同期に依存している場合はロードされた依存関係。エクスポートはトップレベルである必要があるため、エクスポートする方法はありません。

Webpackには、依存関係Xが必要に応じてオンデマンドでロードされ、それをインポートするインポートされたモジュールがインポートプロセスを透過的に待機することを示す方法はありませんか?このユースケースは、リモートで大規模なアプリケーションのsine qua nonになると思うので、何かが足りないと思う必要があります。

更新2

Peterの回答によると、commonChunkプラグインはエンドポイント間でのコードの共有に関連しており、require.ensureはロードされたコードをコールバックに配置するため、重複排除を機能させようとしました。これにより、ES6 exportingに依存するコード。

重複排除に関しては、contacts.jstasks.jsの両方が同じsharedUtilをロードします。

import SharedUtil1 from '../../sharedUtilities/sharedUtility1';

私はwebpackをとして実行してみました

webpack --optimize-dedupe

また、追加することによって

plugins: [
    new webpack.optimize.DedupePlugin()
]

webpack.configに。どちらの場合も、sharedUtilコードは引き続き連絡先バンドルとタスクバンドルの両方に配置されます。

16
Adam Rackis

あなたのブログ投稿を読んだ後、私はついにあなたが意図したことを理解しました。 「トップレベルの依存関係」という言葉に少し混乱しました。

2つのモジュール(async-aasync-b)があり、どこからでもオンデマンドでロードされ(ここではモジュールmain)、両方とも共有モジュール(shared)。

- - -> on-demand-loading (i. e. System.import)
---> sync loading (i. e. import)

main - - -> async-a ---> shared
main - - -> async-b ---> shared

デフォルトでは、webpackは次のようなチャンクツリーを作成します。

---> chunk uses other chunk (child-parent-relationship)

entry chunk [main] ---> on-demand chunk 1 [async-a, shared]
entry chunk [main] ---> on-demand chunk 2 [async-b, shared]

これは、shared <async-a/bの場合、またはasync-aasync-bの両方が同じユーザーによって使用される可能性が低い場合に問題ありません。これは最も単純な動作であり、おそらく予想される動作であるため、デフォルトです。1つのSystem.import => 1つのチャンクです。私の意見では、それは最も一般的なケースでもあります。

ただし、shared> = async-a/bであり、ユーザーがasync-aasync-bをロードする可能性が高い場合は、より効率的なチャンク化オプションがあります:(少し難しい視覚化する):

entry chunk [main] ---> on-demand chunk 1 [async-a]
entry chunk [main] ---> on-demand chunk 2 [async-b]
entry chunk [main] ---> on-demand chunk 3 [shared]

When main requests async-a: chunk 1 and 3 is loaded in parallel
When main requests async-b: chunk 2 and 3 is loaded in parallel
(chunks are only loaded if not already loaded)

これはデフォルトの動作ではありませんが、アーカイブするためのプラグインがあります:非同期モードのCommonChunkPlugin。チャンクの束の中から共通/共有モジュールを見つけ、共有モジュールを含む新しいチャンクを作成します。非同期モードでは、元の(ただし現在は小さい)チャンクと並行して新しいチャンクをロードします。

new CommonsChunkPlugin({
    async: true
})

// This does: (pseudo code)
foreach chunk in application.chunks
  var shared = getSharedModules(chunks: chunk.children, options)
  if shared.length > 0
    var commonsChunk = new Chunk(modules: shared, parent: chunk)
    foreach child in chunk.children where child.containsAny(shared)
      child.removeAll(shared)
      foreach dependency in chunk.getAsyncDepenendenciesTo(child)
        dependeny.addChunk(commonsChunk)

CommonsChunkPluginには、モジュールがいつスレッド化されるかをminChunksとして定義するsharedオプションがあることに注意してください(モジュールを選択するためのカスタム関数を自由に提供してください)。

セットアップと出力を詳細に説明する例を次に示します。 https://github.com/webpack/webpack/tree/master/examples/extra-async-chunk

そして、より多くの構成を持つ別のもの: https://github.com/webpack/webpack/tree/master/examples/extra-async-chunk-advanced

15
Tobias K.

私があなたを正しく理解していれば、異なるコードチャンクが依存関係として宣言したときに同じ依存関係が複数回読み込まれるのを防ぎたいと思います。

はい、これは可能です。それを行う方法は、アプリケーションのコンテキストと、ES6またはES5のどちらにあるかによって異なります。

ECMAスクリプト5

Webpack1はECMAScript 5で構築されており、通常、モジュールのエクスポートとインポートにCommonJSまたはRequireJS構文のいずれかを使用します。この構文を使用する場合、次の機能を使用してコードの重複を防ぐことができます。

  • 重複排除は、重複関数を再定義する代わりにコピーを作成することにより、コンパイルされたコードに重複ファイルが含まれるのを防ぎます。
  • 名前付きチャンクを使用すると、チャンクを依存関係として宣言できますが、すぐには評価されません。同じチャンクのすべてのオカレンスは同じインスタンスを使用します。
  • CommonsChunkPluginを使用すると、チャンクを複数のエントリポイント間で共有できます(複数のページのWebサイトにのみ適用されます)。

重複排除

webpackドキュメント から:

クールな依存関係ツリーを持つライブラリを使用すると、一部のファイルが同一になる場合があります。 Webpackはこれらのファイルを見つけて、重複排除することができます。これにより、重複するコードがバンドルに含まれるのを防ぎ、代わりに実行時に関数のコピーを適用します。 セマンティクスには影響しません。

強調は私のものであり、ソースからではありません

ドキュメントに記載されているように、コード分割は変更されません。 _sharedUtil1_を必要とする各モジュールは、通常どおりrequireを宣言する必要があります。同じ依存関係が複数回読み込まれるのを防ぐために、実行時にファイルを含める前に、webpackがファイルの重複を明示的にチェックするようにするwebpack設定が有効になっています。

このオプションは、_--optimize-dedupe_ respで有効になります。 new webpack.optimize.DedupePlugin()

名前付きチャンク

webpackドキュメント から:

_require.ensure_関数は、追加の3番目のパラメーターを受け入れます。これは文字列でなければなりません。 2つのスプリットポイントが同じ文字列を渡す場合、それらは同じチャンクを使用します... _require.include_は、モジュールが複数の子チャンクにある場合に役立ちます。親の_require.include_にはモジュールが含まれ、子チャンクのモジュールのインスタンスは表示されなくなります。

つまり、モジュールのロードはコンパイルの後半まで延期されます。これにより、重複する定義を含める前に削除できます。ドキュメントには例が記載されています。

共通チャンクプラグイン

webpackドキュメント から:

CommonsChunkPluginは、複数のエントリチャンクで発生するモジュールを新しいエントリチャンク(コモンズチャンク)に移動できます。ランタイムもコモンズチャンクに移動されます。これは、古いエントリチャンクが最初のチャンクになったことを意味します。

これは、複数のページ間でチャンクを共有することに非常に固有であり、他の状況では関係ありません。

ECMAスクリプト6

高度なモジュールインポート機能のサポートは...進行中の作業です。物事がどこにあるかを知るには、次のリンクを参照してください。

ES6モジュールとwebpackの概要は次のとおりです。 TypeScriptとWebpackを備えたES6モジュール

上記の情報はすぐに古くなる可能性があります。

提案

あなた自身の正気のために、私は提案します:

最適化が重要な場合:Webpack 2が安定してリリースされたら、CommonJS/RequireJS構文に戻し、ECMA Script6にアップグレードします。

ECMA Script 6構文が重要な場合:標準のECMA Script 6インポートエクスポート形式を使用し、利用可能になったときに最適化機能を追加します。

シル不安定なwebpack2で高度なモジュール読み込み機能を試して使用するには、フラックスが多すぎます。問題が解決し、いくつかの本当に優れたプラグインが利用可能になるのを待ってから、試してみてください。

11
Marvin

Webpackの作成者によると、これは不可能です。簡潔でシンプル。 WebpackとES6に関するその他の優れた情報については、Peterの回答を参照してください。

貼り付けた画像は誤解によるものです。上記の同じユーザーの回答を参照してください。

enter image description here

1
Adam Rackis

_System.import_はWebpackで非推奨になりました。 Webpackは、promiseにポリフィルを必要とするimport()を優先するようになりました。

コード分割-import()を使用

0
Josh