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

Posted

技术标签:

【中文标题】如何配置 webpack 4 以防止入口点列表中的块出现在任何其他包中?【英文标题】:How to configure webpack 4 to prevent chunks from list of entry points appearing in any other bundle? 【发布时间】:2018-08-16 05:59:56 【问题描述】:

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

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

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

现在随着 webpack 4 和 CommonsChunkPlugin 的移除,我不清楚如何完成这种优化。

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

我已经建立了一个小型 repo 作为修改的起点:https://github.com/lencioni/webpack-splitchunks-playground

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

您当前的配置(使用 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'
            
        
    

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


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

更多关于code splitting and the splitChunks optimization的信息

【讨论】:

感谢您参与并整理 PR!不幸的是,这不是我所需要的。我需要一个解决方案,在不创建新资产的情况下将块保留在这些核心捆绑包中。我会尝试进一步澄清我的问题。 我想这可能是我需要的。我需要做更多的测试,但它似乎非常接近。 github.com/lencioni/webpack-splitchunks-playground/pull/3 好的。我刚查了!所以,我错过了最初的意图。你不想在入口点之外创建任何其他包,甚至对于供应商也不行,相反,那些第三方依赖项应该保留在一个或多个核心包中。我可能会遵循相同的路径,在入口点上的每个 core* 上创建一个条目。干杯!【参考方案3】:

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

【讨论】:

以上是关于如何配置 webpack 4 以防止入口点列表中的块出现在任何其他包中?的主要内容,如果未能解决你的问题,请参考以下文章

Webpack 2 未解析 webpack.config.js 中的入口点

如何为 Webpack 中的每个入口点重命名 output.library 选项?

Webpack,多个入口点 Sass 和 JS

webpack工作流程

Webpack 4 学习03(配置入口和出口的进阶使用)

未找到入口模块中的错误 - 在 Webpack 配置文件中