Плагин 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 вызов, чтобы указать поведение загрузки.

Другие вопросы по тегам