如何配置 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 中的入口点