web-dev-qa-db-ja.com

ベンダのスクリプトを別にまとめてWebpackで必要に応じてそれらを要求するにはどうすればいいですか?

私は可能であるべきと信じる何かをやろうとしています、しかし、私は本当にWebpackドキュメンテーションからそれをする方法を理解することができません。

私はお互いに依存するかもしれないしないかもしれないいくつかのモジュールを含むJavaScriptライブラリを書いています。それに加えて、jQueryはすべてのモジュールによって使用され、それらのいくつかはjQueryプラグインを必要とするかもしれません。このライブラリは、いくつかまたはすべてのモジュールを必要とするかもしれないいくつかの異なるWebサイトで使用されます。

私のモジュール間の依存関係を定義することは非常に簡単でした、しかし彼らの第三者の依存関係を定義することは私が予想したより難しいように思えます。

達成したいこと:各アプリに、必要なサードパーティの依存関係を持つ2つのバンドルファイルと、必要なモジュールを含む2つのバンドルファイルが必要です。私の図書館.

:私のライブラリには以下のモジュールがあるとしましょう。

  • a (requires: jquery, jquery.plugin1)
  • b (requires: jquery, a)
  • c (requires: jquery, jquery.ui, a, b)
  • d (requires: jquery, jquery.plugin2, a)

そして、私はモジュールa、b、cを必要とするアプリ(それをユニークなエントリーファイルと見てください)を持っています。この場合のWebpackは以下のファイルを生成します。

  • ベンダーバンドル:jquery、jquery.plugin1、およびjquery.uiを使用。
  • ウェブサイトのバンドル:モジュールa、b、c。

結局、jQueryをグローバルにしたいので、すべての単一ファイルにjQueryを要求する必要はありません(たとえば、メインファイルにのみ要求することもできます)。そしてjQueryプラグインはそれらが必要とされる場合には$ globalを単に拡張するでしょう(それらがそれらを必要としない他のモジュールに利用可能であれば問題ではありません)。

これが可能であると仮定して、この場合のwebpack設定ファイルの例は何でしょうか?私は自分の設定ファイル上でローダー、外部、そしてプラグインのいくつかの組み合わせを試してみましたが、それらが何をしているのか、そしてどれを使うべきなのか実際にはわかりません。ありがとうございました!

163
Anakin

私のwebpack.config.js(バージョン1,2,3)ファイルには、

function isExternal(module) {
  var context = module.context;

  if (typeof context !== 'string') {
    return false;
  }

  return context.indexOf('node_modules') !== -1;
}

私のプラグイン配列で

plugins: [
  new CommonsChunkPlugin({
    name: 'vendors',
    minChunks: function(module) {
      return isExternal(module);
    }
  }),
  // Other plugins
]

今私は必要に応じて1つのファイルにサードパーティ製のライブラリを追加するだけのファイルがあります。

ベンダーとエントリポイントファイルを分ける場所をもっと細かくしたい場合は、

plugins: [
  new CommonsChunkPlugin({
    name: 'common',
    minChunks: function(module, count) {
      return !isExternal(module) && count >= 2; // adjustable
    }
  }),
  new CommonsChunkPlugin({
    name: 'vendors',
    chunks: ['common'],
    // or if you have an key value object for your entries
    // chunks: Object.keys(entry).concat('common')
    minChunks: function(module) {
      return isExternal(module);
    }
  })
]

プラグインの順序は非常に重要です。

また、これはバージョン4でも変更される予定です。公式になったら、この回答を更新します。

更新:windowsユーザーのindexOf検索の変更

135
Rafael De Leon

私はあなたの問題を完全に理解しているかどうかはわかりませんが、私は最近同様の問題を抱えていたので私はあなたを助けようとします。

ベンダーバンドル。

そのためには CommonsChunkPlugin を使うべきです。設定では、チャンクの名前(vendorなど)と生成されるファイル名(vendor.js)を指定します。

new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),

重要な部分は、vendorライブラリとはどういう意味かを指定する必要があります。それをエントリセクションで行います。新しく宣言されたチャンクの名前と同じ名前を持つエントリリストへのもう1つの項目(つまり、この場合は 'vendor')。そのエントリの値はあなたがvendorバンドルに移動したいすべてのモジュールのリストであるべきです。あなたの場合は、次のようになります。

entry: {
    app: 'entry.js',
    vendor: ['jquery', 'jquery.plugin1']
}

グローバルとしてのJQuery

同じ問題があり、 ProvidePlugin で解決しました。ここではグローバルオブジェクトを定義しているのではなく、モジュールへの種類の縮小を定義しています。つまり、次のように設定できます。

new webpack.ProvidePlugin({
    $: "jquery"
})

そして今、あなたはコードのどこでも$を使うことができます - ウェブパックは自動的にそれをに変換します

require('jquery')

お役に立てば幸いです。また、私のWebPackの設定ファイルを見てください。これは here です。

私はwebpackが大好きですが、ドキュメントが世界で最も素晴らしいものではないことに同意します...でもちょっと..人々は初めにAngularドキュメントについて同じことを言っていました:)


編集:

エントリポイント固有のベンダーチャンクを作成するには、単にCommonsChunkPluginsを複数回使用します。

new webpack.optimize.CommonsChunkPlugin("vendor-page1", "vendor-page1.js", Infinity),
new webpack.optimize.CommonsChunkPlugin("vendor-page2", "vendor-page2.js", Infinity),

そして、ファイルごとに異なる外部ライブラリを宣言します。

entry: {
    page1: ['entry.js'],
    page2: ['entry2.js'],
    "vendor-page1": [
        'lodash'
    ],
    "vendor-page2": [
        'jquery'
    ]
},

いくつかのライブラリがエントリポイント間で(そしてほとんどの場合)オーバーラップしている場合は、異なる設定の同じプラグインを使用してそれらを共通ファイルに抽出できます。 this exampleを参照してください。

51
Michał Margiel

あなたが自動的にあなたのスクリプトをベンダーのものとは別にバンドルすることに興味があるならば:

var webpack = require('webpack'),
    pkg     = require('./package.json'),  //loads npm config file
    html    = require('html-webpack-plugin');

module.exports = {
  context : __dirname + '/app',
  entry   : {
    app     : __dirname + '/app/index.js',
    vendor  : Object.keys(pkg.dependencies) //get npm vendors deps from config
  },
  output  : {
    path      : __dirname + '/dist',
    filename  : 'app.min-[hash:6].js'
  },
  plugins: [
    //Finally add this line to bundle the vendor code separately
    new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.min-[hash:6].js'),
    new html({template : __dirname + '/app/index.html'})
  ]
};

この機能についての詳細は 公式文書 で読むことができます。

39
Freezystem

私があなたのケースを完全に理解しているかどうかもわからない、しかしここにあなたのバンドルの各々のために別々のベンダーチャンクを作成するための設定断片がある:

entry: {
  bundle1: './build/bundles/bundle1.js',
  bundle2: './build/bundles/bundle2.js',
  'vendor-bundle1': [
    'react',
    'react-router'
  ],
  'vendor-bundle2': [
    'react',
    'react-router',
    'flummox',
    'immutable'
  ]
},

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle1',
    chunks: ['bundle1'],
    filename: 'vendor-bundle1.js',
    minChunks: Infinity
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle2',
    chunks: ['bundle2'],
    filename: 'vendor-bundle2-whatever.js',
    minChunks: Infinity
  }),
]

そしてCommonsChunkPlugin docsへのリンク: http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin

11
Alex Fedoseev