СТАТЬЯ KOBEZZZA.LAB

Экспериментальные функции webpack

Начиная с 5 версии в webpack добавили механизм, позволяющий использовать новые возможности Webpack заранее, еще до выхода новой версии. Этот механизм называется experiments. Помимо использования новых возможностей, он также позволяет включить новые дефолтные настройки конфига для своего проекта.

Этот механизм можно использовать, чтобы проверить, нужно ли что-то менять в вашей сборки перед выходом новой версии, а можно использовать эти экспериментальные возможности прямо сейчас.

Разберем все экспериментальные возможности Webpack которые можно использоваться прямо сейчас.

Важно
При использовании experiment нужно точно фиксировать версию Webpack в вашем проекте, использовать тильду перед указанием версии в package.json ~5.70.0 для обновления только на минорный релиз или явно фиксировать версию 5.70.0. Это необходимо сделать, так как экспериментальные возможности могут получить breaking change в любой момент и разработчики не гарантирую стабильность API.
Опции
Для включения экспериментальной возможности в корне конфига нужно добавить поле experiments:

module.exports = {
    //...
    experiments: {
        //...
    }
}
futureDefaults
При указании этой опции, Webpack использует дефолтные настройки конфига из будущей версии Webpack.

module.exports = {
    //...
    experiments: {
        futureDefaults: true
    }
}
Список новых дефолтов
  • parserOptions.exportsPresence: 'error' - генерирует ошибку при отсутствии искомого export в файле, сейчас по умолчанию warning
  • output: xxhash64 - меняет алгоритм генерации хэша для файлов на xxhash64 самый современный и быстрый алгоритм хэширования, сейчас алгоритм md4
  • output.hashDigestLength: 16 - устанавливает длину хэша 16 в имени файла, сейчас 20
  • node.global: 'warn' - управляет тем, нужно ли полифиллить глобальные константы из node.js (__filename, __dirname). Сейчас по умолчанию true, в futureDefaults режиме генерирует warning, а в webpack 6 полифиллинг будет отключен
  • node.__filename: 'warn'
  • node.__dirname: 'warn'
  • experiments.backCompat: true - показывает различные warning при использовании старых api webpack
  • experiments.asyncWebAssembly: true - поддержка последнего стандарта интеграции .wasm на веб страницу
  • experiments.cacheUnaffected: true - ускорение горячей сборки
  • experiments.css - нативная сборка css по умолчанию
asyncWebAssembly
Опция реализует спецификацию https://github.com/WebAssembly/esm-integration и делает .wasm модули по умолчанию ассинхронными.

module.exports = {
    experiments: {
        asyncWebAssembly: true
    }
}
  • parserOptions.exportsPresence: 'error' - генерирует ошибку при отсутствии искомого export в файле, сейчас по умолчанию warning
  • output: xxhash64 - меняет алгоритм генерации хэша для файлов на xxhash64 самый современный и быстрый алгоритм хэширования, сейчас алгоритм md4
  • output.hashDigestLength: 16 - устанавливает длину хэша 16 в имени файла, сейчас 20
  • node.global: 'warn' - управляет тем, нужно ли полифиллить глобальные константы из node.js (__filename, __dirname). Сейчас по умолчанию true, в futureDefaults режиме генерирует warning, а в webpack 6 полифиллинг будет отключен
  • node.__filename: 'warn'
  • node.__dirname: 'warn'
  • experiments.backCompat: true - показывает различные warning при использовании старых api webpack
  • experiments.asyncWebAssembly: true - поддержка последнего стандарта интеграции .wasm на веб страницу
  • experiments.cacheUnaffected: true - ускорение горячей сборки
  • experiments.css - нативная сборка css по умолчанию
buildHttp
Опция добавляет в Webpack поддержку синтаксиса импортов по https:

import React from 'https://esm.sh/react'
Например, можно импортировать готовые esm модули с таких сервисов как https://skypack.dev или https://esm.sh.

module.exports = {
    experiments: {
        buildHttp: {
            // разрешенные URL для загрузки
            allowedUris: (string|RegExp|(uri: string) => boolean)[];

            // местонахождение кэша с загруженными модулями на файловой системе
            // по умолчанию <compiler-name.>webpack.lock.data/
            // нужно добавить эту папку в систему контроля версии
            // так как в production сборке webpack не ходит в сеть
            cacheLocation?: false | string;

            // создает для https модулей lock файл (тот же механизм, что и yarn.lock или package-lock.json)
            // в случае несовпадения хэша генерирует ошибку
            // также нужно добавлять в систему контроля версии
            frozen?: boolean;

            // имя lock файла
            // по умолчанию <compiler-name.>webpack.lock
            lockfileLocation?: string;

            // проверяет обновление у зависимости и устанавливает его автоматически
            upgrade?: boolean;

            // позволяет указать proxy для запросов за зависимостями
            proxy?: string;
        }
    }
}

CSS
Включает нативную поддержку css. Начиная с 6 версии webpack по умолчанию будет сам собирать css без необходимости использования сторонних лоадеров и плагинов.

module.exports = {
    //...
    experiments: {
        css: true
    }
}

Возможности
  • поддержка css модулей. Файл должен называться <name>.module.css
  • поддержка поля style в package.json библиотеки для правильного подключения стилей при использовании @import Например, вы используете bootstrap и хотите подключить его в своем css. Для этого вы пишете @import 'bootstrap'. Webpack использует содержимое package.json в node_modules/bootstrap и подключит файл указанный в поле style, если поля style нет, то будет использоваться стандартное поле main.
  • генерация contenthash у файлов, включена по умолчанию
  • генерация .css файлов: заменяет собой css-loader и mini-css-extract-plugin
  • поддержка Hot Module Replacement
Также есть режим работы exportsOnly, который не собирает .css, а лишь добавляет в .js файлы экспорты из .css (подразумевается, что .css вы собираете каким-то другим образом).

module.exports = {
    //...
    experiments: {
        css: {
            exportsOnly: true
        }
    }
}
cacheUnaffected
Опция ускоряет горячую пересборку.
Webpack более точно определяет какие модули были не затронуты внесенным изменением и не пересобирает их.

module.export = {
    //...
    experiments: {
        cacheUnaffected: true
    },
    // также нужно включить опцию в настройках кэша
    cache: {
        // работает только для type memory
        type: 'memory',
        cacheUnaffected: true,
    },
}
lazyCompilation
Опция позволяет Webpack лениво собирать модули. При таком режиме, Webpack собирает код только при получении запроса за ним. Например, можно настроить, чтобы ассинхронные импорты (динамически загружаемые чанки) собирались только при получении запроса.
Так как Webpack нужно знать, какие именно модули были запрошены, опция работает только в комбинации с devServer:

module.exports = {
    mode: "development",
    entry: {
        main: "./example.js"
    },
    cache: {
        type: "filesystem",
        idleTimeout: 5000
    },
    experiments: {
        lazyCompilation: true
    },
    devServer: {
        hot: true,
        publicPath: "/dist/"
    },
    plugins: [new HotModuleReplacementPlugin()]
}
Это существенно ускоряет сборку и пересборку, но создает задержку, при открытии веб страницы.

С помощью опции можно настраивать степень ленивости:

module.exports = {
    experiments: {
        lazyCompilation: {
            // выключает ленивую сборку для динамических импортов
            entries?: boolean,

            // выключает ленивую сборку для entry
            imports?: boolean,

            // выключает ленивую сборку для модулей по регулярному выражению
            test?: string | RegExp | ((module: Module) => boolean)
        }
    }
}
Также режим бесполезен, если у вас один entry и нет динамических импортов, поэтому старайтесь дробить ваш код на динамический код / множество entry.

Помимо возможности настраивать ленивость для каждого модуля в отдельности, можно кастомизировать поведение клиента и опции запуска lazy сервера:

module.exports = {
    experiments: {
        lazyCompilation: {
            backend: {
                // путь до кастомного клиента (код который синхроинизирует ленивую сборку с клиентской страницей)
                // по умолчанию это https://github.com/webpack/webpack/blob/main/hot/lazy-compilation-web.js
                client?: string;
            
                // параметры запуска сервера (используется обычный модуль http/https createServer из node.js)
                listen?: number | ListenOptions | ((server: typeof Server) => void);

                // протокол для взаимодействия клиента с сервером
                protocol?: "http" | "https";

                // параметры создания сервера, отвечающего за ленивую сборку или сам инстанс сервера
                server?: ServerOptionsImport | ServerOptionsHttps | (() => typeof Server);
            }
        }
    }
}
Или вовсе использовать самописный бэкенд для сборки:
module.exports = {
    experiments: {
        lazyCompilation: {
            // функция самого webpack: https://github.com/webpack/webpack/blob/main/lib/hmr/lazyCompilationBackend.js
            backend: (compiler: Compiler, callback: (err?: Error, api?: BackendApi) => void) => void
        }
    }
}
outputModule
При включении опции Webpack будет генерировать бандл с использованием ECMAScript синтаксиса модулей (import(), export).

module.exports = {
    experiments: {
        outputModule: true,
    },
};
topLevelAwait
Включает поддержку top level await
Позволяет использовать await вне async функции. Webpack преобразует такие модули в async.

По умолчанию включен начиная с версии 5.83.0.

module.exports = {
    //...
    experiments: {
        topLevelAwait: true
    }
}
При использовании experiment нужно точно фиксировать версию Webpack в вашем проекте, использовать тильду перед указанием версии в package.json ~5.70.0 для обновления только на минорный релиз или явно фиксировать версию 5.70.0. Это необходимо сделать, так как экспериментальные возможности могут получить breaking change в любой момент и разработчики не гарантирую стабильность API.
Итого
В экспериментальных функциях Webpack много интересного, что может вам пригодиться. lazyCompilation позволяет существенно ускорить сборку, поддержка import from 'https://...' позволяет использовать import type module уже сейчас для старых браузеров, а futureDefaults плавно подготовиться к новому релизу Webpack, чтобы в будущем было проще обновить Webpack.
Если интересуешься темой
инфраструктуры, то не пропусти
приглашаем на курс
Продвинутое использование Webpack
Cтарт 5 декабря