WebpacksplitChunks插件-为什么设置区块的优先级会使其初始化异步




我在理解Webpack splitChunks插件的行为时遇到问题。我正在做的是将现有网站上的旧脚本重写为组件,并使用Webpack进行绑定。捆绑包只是JS,大多数都是在主体的末尾加载的。但是,一个小脚本需要在页面的页眉中,因为它还创建了一些稍后在页眉和正文中使用的全局方法,主要是作为内联脚本。由于它用于GA跟踪,因此不会更改,必须尽快发送事件。

以下配置对我有效,但问题是为什么它只能以这种方式工作

确切的问题在下面代码的注释中,但我也把它放在这里:我不明白为什么有必要把!isUsedInAppHeader也包括在common块的条件中。在没有!isUsedInAppHeader的情况下,不创建common.header块。然后,当我试图通过为common.header块添加更高的优先级来修复它时,它会导致app.header.js中脚本的异步初始化

异步行为是我完全不理解的,因为它在app.js中从未发生过。

实际上,我还有一个小问题。是否可以导出一个也立即初始化自身的公共块?或者你会提出另一个解决方案吗?标头中的脚本不能移动,也必须同步初始化,因为它的主要作用是创建GA跟踪的全局方法,这些方法现在和必须立即在下面的代码中使用。

谢谢!

Webpack配置:

...
gulp.task('webpack', function(callback) {
var settings = {
...
entry: {
'app.header':   './js/app.header.js',
'app':          './js/app.js',
... // page specific files etc.
},
...
optimization: {
splitChunks: {
cacheGroups: {
// Node modules used in app.js
vendorsApp: {
test(module, chunks) {
let isInAppEntryPoint = chunks.map(chunk => chunk.name).includes('app');
let isNodeModule = //node_modules//.test(upath.normalize(module.resource));
return isInAppEntryPoint && isNodeModule;
},
name: 'vendors',
chunks: 'all',
enforce: true,
},
// Modules shared between app.header and any other file
commonHeader: {
test(module, chunks) {
let isUsedInHeader = chunks.map(chunk => chunk.name).includes('app.header');
return isUsedInHeader;
},
name: 'common.header',
chunks: 'initial',
minChunks: 2,
minSize: 0,
// priority: 2  // (*)
},
// Modules shared between app.js and any other file
common: {
test(module, chunks) {
// QUESTION I don't understand why is it necessary to also include !isUsedInAppHeader into the condition.
//          Without the !isUsedInAppHeader in the condition no common.header chunk is created.
//          Then, when I try to fix it via adding priority (*) for common.header, it results
//          in asynchronous initialisation of the scripts in the app.header.js
let isUsedInApp = chunks.map(chunk => chunk.name).includes('app');
let isUsedInAppHeader = chunks.map(chunk => chunk.name).includes('app.header');
return isUsedInApp && !isUsedInAppHeader;
},
name: 'common',
chunks: 'initial',
minChunks: 2,
},
}
}
},
};
var bundle = webpack(settings, function(error, stats) {
...
});
return bundle;
});

这是在页面中加载脚本的方式:

<!DOCTYPE html>
<html lang="en">
<head>
...
<script src="/js/common.header.js"></script>
<script src="/js/app.header.js"></script>
<script>
... // Immediate calling of some of the the global methods defined in app.header
</script>
</head>
<body>
...
<script src="/js/vendors.js"></script>
<script src="/js/common.js"></script>
<script src="/js/app.js"></script>
<script src="..."></script>  // page specific files etc.
</body>
</html>

正如SplitChucks插件所说:

默认情况下,它只影响按需块,因为更改初始块会影响HTML文件运行项目时应包含的脚本标记。

要使事情更符合您的意愿,您需要使用默认的chunks: async设置,这样初始块将保留在您的入口点中。我相信您的设置中的另一个选项是将chunks: all用于公共。如果你想走这条路,请查阅本指南。

但我不建议采取这种策略。由于大多数cdn支持webpack4和HTML2,最好让webpack自动分割块,以及通过导入语法定义的异步、延迟加载部分。。

因此,您有一个入口点,以及您明确指定的代码拆分点。如果您不想在您的webpack构建中支持es6模块导入,则需要确保您可以使用语法。如果你的代码库没有强迫你使用它,我不推荐它。

通过魔术注释预加载是import.then()语法的另一个好处。在import调用中添加一个类似/* webpackHint */的注释前缀,以指示加载行为。

最新更新