30

我正在做一个大型项目并尝试登陆 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

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

4

3 回答 3

12

好的,所以我想我已经想出了如何做到这一点。但首先,这是使用默认 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
于 2018-03-14T15:45:44.117 回答
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.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'
            }
        }
    }
}

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


您可以在此处查看工作代码。我还为您的示例项目创建了一个拉取请求。

有关代码拆分和 splitChunks 优化的更多信息

于 2018-03-11T21:28:55.537 回答
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
                    }
                }
            }
        },
于 2018-03-11T21:24:26.257 回答