如何配置webpack 4以防止出现在任何其他捆绑包中的入口点列表中的块?

时间:2018-03-08 00:51:51

标签: webpack webpack-4

我正在开展一个大型项目并试图登陆webpack 3 - > 4更新。这个应用程序有大约1,000个入口点,其中大约10个被认为是“全局”或“核心”,并保证在每个页面上。这些核心包包含供应商和非供应商代码的混合。我需要配置webpack来构建所有这些资产,以便任何这些捆绑包中出现的任何块都不会出现在任何其他捆绑包中,无论块的大小如何,而无需创建需要添加到页面的新资产。 / p>

使用webpack 3,我们一直在使用CommonsChunkPlugin来实现这一目标。这是一个简单的例子:

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

现在有了webpack 4并删除了CommonsChunkPlugin,我不清楚如何完成这种优化。

我希望能够为webpack提供一个入口点列表,任何出现在其中的任何块都不会出现在任何其他捆绑包中,但我不知道如何做到这一点。我已阅读some forthcoming documentation on splitChunks,但我无法拼凑出一个解决方案。

我已经设置了一个小型仓库作为修补的起点:https://github.com/lencioni/webpack-splitchunks-playground

我正在尝试的一个有趣方向是为每个入口点配置一个cacheGroups组,并使用执行此检查的函数实现test选项。但是,文档在这方面非常稀少,所以我不确定编写此测试函数的正确方法是什么,或者即使这样也可以。

3 个答案:

答案 0 :(得分:11)

好的,所以我想我已经弄清楚如何做到这一点。但首先,这是使用默认的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

如果目标是使核心,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

答案 1 :(得分:3)

您当前的配置(使用Webpack 3)使用CommonsChunkPlugin Explicit vendor chunk

  

将代码拆分为供应商和应用程序。

检查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.jsconsole.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'
            }
        }
    }
}

在捆绑包之间生成非重复代码。

您可以查看工作代码here。 我还为您的示例项目创建了pull request

有关code splitting and the splitChunks optimization

的更多信息

答案 2 :(得分:1)

  

我们的目标是配置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
                    }
                }
            }
        },