Плагин Webpack SplitChunks - почему установка приоритета чанка делает его инициализацию асинхронной?
У меня проблемы с пониманием поведения плагина Webpack splitChunks. Я работаю над переписыванием старых скриптов на существующем сайте в компоненты и использованием Webpack для объединения. Связки просто JS, большинство загружается в конце тела. Но один маленький скрипт должен быть в заголовке страницы, так как он также создает несколько глобальных методов, используемых позже в заголовке и в теле, в основном в виде встроенных скриптов. Поскольку он используется для отслеживания GA, он не изменится, события должны быть отправлены как можно скорее.
Следующая конфигурация работает для меня, но вопрос в том, почему она работает только так?
Точный вопрос в комментарии в коде ниже, но я также выкладываю его здесь: я не понимаю, почему необходимо также включать !isUsedInAppHeader
в состояние для common
Кусок. Без !isUsedInAppHeader
в состоянии нет common.header
чанк создан. Затем, когда я пытаюсь это исправить, добавив более высокий приоритет для common.header
это приводит к асинхронной инициализации сценариев в app.header.js
,
Асинхронное поведение - это то, чего я вообще не понимаю, так как это никогда не происходит в app.js
,
У меня есть другой вопрос, на самом деле. Можно ли экспортировать общий блок, который также сразу инициализируется? Или вы бы предложили другое решение вообще? Скрипты в заголовке не могут быть перемещены и должны также инициализироваться синхронно, поскольку его основная роль заключается в создании глобальных методов для отслеживания GA, которые должны и должны использоваться немедленно в следующем коде.
Спасибо!
Конфигурация веб-пакета:
...
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>
1 ответ
Как говорит плагин SplitChunks:
По умолчанию это влияет только на чанки по требованию, так как изменение начальных чанков повлияет на теги сценария, которые HTML-файл должен включать для запуска проекта.
Чтобы все работало так, как вы хотите, вы хотите использовать настройки по умолчанию chunks: async
установка, таким образом, начальные куски будут оставаться в ваших точках входа. Я полагаю, что другой вариант в вашей настройке будет использовать chunks: all
для общего. Если вы хотите пойти по этому пути, обратитесь к этому руководству.
Но я не рекомендую эту стратегию. Поскольку webpack4 и HTML2 поддерживаются большинством cdns, лучше разрешить webpack автоматически разбивать фрагменты и асинхронно загруженные части, которые вы определяете с помощью синтаксиса импорта.,
Таким образом, у вас есть 1 точка входа и точки разделения кода, которые вы указываете явно. Если вы не хотите поддерживать импорт модуля es6 в сборке вашего веб-пакета, вы можете использовать синтаксис require.ensure. Я не рекомендую это, если ваша кодовая база не заставляет вас использовать это.
Предварительная загрузка с помощью волшебных комментариев является еще одним преимуществом import.then()
синтаксис. Вы добавляете префикс комментария как /* webpackHint */
к import
вызов, чтобы указать поведение загрузки.