web-dev-qa-db-ja.com

他のバンドルに表示されるエントリポイントのリストからチャンクを防ぐためにwebpack 4を構成する方法は?

私は大規模なプロジェクトに取り組んでおり、webpack 3-> 4アップデートを取得しようとしています。このアプリには約1,000個のエントリポイントがあり、そのうち約10個は「グローバル」または「コア」と見なされ、すべてのページに存在することが保証されています。これらのコアバンドルには、ベンダーコードと非ベンダーコードが混在しています。これらのバンドルのすべてに表示されるチャンクが、ページに追加する必要のある新しいアセットを作成せずに、チャンクのサイズに関係なく他のバンドルに表示されないように、これらすべてのアセットを構築するようにwebpackを構成する必要があります。

Webpack 3では、これを実現するためにCommonsChunkPluginを使用しています。以下に簡単な例を示します。

new webpack.optimize.CommonsChunkPlugin({
  name: 'a-global-bundle',
  minChunks: Infinity,
}),

現在、webpack 4とCommonsChunkPluginの削除により、この種の最適化を達成する方法は明確ではありません。

Webpackにエントリポイントのリストを提供し、それらのいずれかに表示されるチャンクは他のバンドルには表示されないようにしたいと思いますが、これを行う方法がわかりません。 splitChunksに関する今後のドキュメント を読みましたが、解決策をまとめることができませんでした。

https://github.com/lencioni/webpack-splitchunks-playground をいじくり回すための出発点として小さなリポジトリを設定しました

私が試している興味深い方向の1つは、これらの各エントリポイントのグループでcacheGroupsを構成し、このチェックを行う関数でtestオプションを実装することです。しかし、ドキュメントはこれについてかなりまばらであるため、このテスト関数を記述する正しい方法が何であるか、またはこれがまったく機能するかどうかは本当にわかりません。

26
Joe Lencioni

わかりましたので、これを行う方法を考え出したと思います。ただし、最初に、デフォルトのsplitChunks構成を使用したビルドの様子を示します(FOO.bundle.jsは動的インポートによって作成された非同期バンドルです)。

            Asset       Size  Chunks                    Chunk Names
   core.bundle.js    605 KiB       0  [emitted]  [big]  core
  coreB.bundle.js    791 KiB       1  [emitted]  [big]  coreB
  coreC.bundle.js    791 KiB       2  [emitted]  [big]  coreC
      a.bundle.js    748 KiB       3  [emitted]  [big]  a
      b.bundle.js    792 KiB       4  [emitted]  [big]  b
      c.bundle.js    674 KiB       5  [emitted]  [big]  c
    FOO.bundle.js  709 bytes       6  [emitted]         FOO
runtime.bundle.js   7.49 KiB       7  [emitted]         runtime

Core、coreB、およびcoreCに表示されるモジュールが他のバンドルに表示されないようにすることが目標である場合、これは次の構成で実行できます。

function coreBundleCacheGroups(coreBundles) {
  const cacheGroups = {};
  const coreChunkNames = Object.keys(coreBundles);
  const coreChunkNamesSet = new Set(coreChunkNames);


  coreChunkNames.forEach((name) => {
    cacheGroups[name] = {
      name,
      chunks: 'all',
      minSize: 0,
      minChunks: 1,
      reuseExistingChunk: true,
      priority: 10000,
      enforce: true,
      test(module, chunks) {
        if (module.depth === 0) {
          return false;
        }

        // Find first core chunk name that matches
        const partOfGlobalChunks = chunks.filter(chunk => coreChunkNamesSet.has(chunk.name));

        if (!partOfGlobalChunks.length) {
          return false;
        }

        const partOfGlobalChunksSet = new Set(partOfGlobalChunks.map(chunk => chunk.name));
        const firstCoreChunkName = coreChunkNames.find(name => partOfGlobalChunksSet.has(name));
        return firstCoreChunkName === name;
      },
    };
  });

  return cacheGroups;
}

const coreBundles = {
  core: './src/bundles/core.js',
  coreB: './src/bundles/core-b.js',
  coreC: './src/bundles/core-c.js',
};

module.exports = {
  mode: 'none',

  entry: {
    ...coreBundles,
    a: './src/bundles/a.js',
    b: './src/bundles/b.js',
    c: './src/bundles/c.js',
  },

  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  optimization: {
    runtimeChunk: 'single',

    splitChunks: {
      cacheGroups: {
        ...coreBundleCacheGroups(coreBundles),
      },
    },
  },
};

次の出力が生成されます。

            Asset       Size  Chunks                    Chunk Names
   core.bundle.js    605 KiB       0  [emitted]  [big]  core
  coreB.bundle.js    188 KiB       1  [emitted]         coreB
  coreC.bundle.js    1.5 KiB       2  [emitted]         coreC
      a.bundle.js   76.4 KiB       3  [emitted]         a
      b.bundle.js   2.28 KiB       4  [emitted]         b
      c.bundle.js   1.91 KiB       5  [emitted]         c
    FOO.bundle.js  622 bytes       6  [emitted]         FOO
runtime.bundle.js   7.49 KiB       7  [emitted]         runtime
11
Joe Lencioni

現在の構成(Webpack 3を使用)は、 明示的なベンダーチャンクCommonsChunkPluginを使用します。

コードをベンダーとアプリケーションに分割します。

repo のWebpack出力を確認する_a.bundle.js_には次のコードが含まれていることがわかりました。

_// `react`, `react-dom` plus
console.log('core module');     // from core-module.js
console.log('core module b');   // from core-module-b.js
console.log('non-core module'); // from non-core-module.js
_

同様のコードは_b.bundle.js_内にあります(このスクリプトの違いは、_console.log_から参照される最後の_non-core-module-b.js_です:console.log('non-core module b');)。

_webpack.config.js_最適化オプションの更新:

_optimization: {
    runtimeChunk: 'single',

    splitChunks: {
        chunks: 'all',

        cacheGroups: {
            default: {
                enforce: true,
                priority: 1
            },
            vendors: {
                test: /[\\/]node_modules[\\/]/,
                priority: 2,
                name: 'vendors',
                enforce: true,
                chunks: 'all'
            }
        }
    }
}
_

バンドル間に非重複コードを生成します。


作業コードを確認できます こちら 。また、サンプルプロジェクトに対して pull request を作成しました。

コード分割とsplitChunks最適化に関する詳細情報

3
Carloluis

私たちの目標は、これらのバンドルのいずれかに表示されるチャンクが他のバンドルに表示されないように、アセットを構築するようにwebpackを構成することです。

私が以前持っていたもの:

            new webpack.optimize.CommonsChunkPlugin({
                name: 'vendor',
                minChunks: function (module, count) {
                    // this assumes your vendor imports exist in the node_modules directory and module should be required
                    // in at least 3 entries before it moved to common chunk
                    return (module.context && module.context.indexOf('node_modules') !== -1) && count > 2;
                }
            }),

現在の仕組み:

        optimization: {
            splitChunks: {
                cacheGroups: {
                    vendor: {
                        test: /[\\/]node_modules[\\/]/,
                        chunks: 'all',
                        name: 'vendor',
                        enforce: true,
                        minChunks: 3
                    }
                }
            }
        },
1
MyTitle