babel-loader — загрузчик для Webpack, предназначенный
для интеграции Babel в процесс сборки проекта. Его основная задача —
преобразование современного JavaScript-кода в версию, совместимую с
более старыми браузерами и окружениями.
Babel выполняет транспиляцию:
Webpack сам по себе не умеет преобразовывать современный JavaScript.
Он только собирает модули. Именно babel-loader связывает
систему сборки с Babel и делает транспиляцию частью пайплайна обработки
файлов.
Для базовой конфигурации требуется установить:
npm install --save-dev babel-loader @babel/core @babel/preset-env
Описание пакетов:
| Пакет | Назначение |
|---|---|
babel-loader |
интеграция Babel с Webpack |
@babel/core |
ядро Babel |
@babel/preset-env |
автоматическая транспиляция под нужные браузеры |
Простейшая конфигурация:
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
};
Здесь:
test определяет тип файлов;exclude исключает обработку зависимостей;babel-loader запускает Babel для каждого JS-файла.Настройки Babel могут храниться:
.babelrc;babel.config.js;package.json;Наиболее распространённый вариант:
{
"presets": ["@babel/preset-env"]
}
Файл .babelrc:
{
"presets": [
"@babel/preset-env"
]
}
@babel/preset-env анализирует:
После этого Babel преобразует только действительно несовместимые конструкции.
Пример исходного кода:
const sum = (a, b) => a + b;
После транспиляции:
"use strict";
var sum = function sum(a, b) {
return a + b;
};
Babel ориентируется на список поддерживаемых браузеров.
Конфигурация в package.json:
{
"browserslist": [
"> 0.25%",
"not dead"
]
}
Пример более строгой поддержки:
{
"browserslist": [
"last 2 versions",
"ie 11"
]
}
Чем старее браузеры в списке, тем больше преобразований выполняет Babel.
Альтернативный способ — настройка внутри Babel:
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"chrome": "90",
"firefox": "88"
}
}
]
]
}
Пример для Node.js:
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "18"
}
}
]
]
}
Транспиляция синтаксиса не добавляет отсутствующие API.
Например:
Promise
Map
Set
Array.from
Для поддержки таких возможностей используются полифилы.
Установка:
npm install core-js regenerator-runtime
Конфигурация:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
| Режим | Описание |
|---|---|
false |
полифилы не подключаются |
entry |
подключаются вручную |
usage |
Babel добавляет только используемые полифилы |
Входной файл:
import "core-js/stable";
import "regenerator-runtime/runtime";
Конфигурация:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry",
"corejs": 3
}
]
]
}
Babel анализирует код и автоматически внедряет только необходимые полифилы.
Исходный код:
const arr = Array.from(document.querySelectorAll('div'));
После сборки Babel может автоматически подключить:
import "core-js/modules/es.array.from.js";
Это уменьшает размер итогового бандла.
Обычно директория зависимостей не транспилируется:
exclude: /node_modules/
Причины:
Однако некоторые пакеты публикуются в ES6-формате. Тогда требуется частичная транспиляция.
Пример:
{
test: /\.js$/,
exclude: /node_modules\/(?!modern-lib)/,
use: 'babel-loader'
}
Здесь:
modern-lib всё же проходит через Babel.Иногда include удобнее:
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
include: [
path.resolve(__dirname, 'src')
],
use: 'babel-loader'
}
]
}
};
Транспиляция может быть медленной. babel-loader
поддерживает файловый кэш.
Пример:
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
Преимущества:
Для корректной отладки:
module.exports = {
devtool: 'source-map'
};
Babel автоматически сохраняет информацию об исходных строках.
Плагины расширяют возможности Babel.
Установка:
npm install --save-dev @babel/plugin-proposal-optional-chaining
Конфигурация:
{
"plugins": [
"@babel/plugin-proposal-optional-chaining"
]
}
Исходный код:
const city = user?.address?.city;
После транспиляции:
var city = user === null || user === void 0
? void 0
: user.address;
Установка:
npm install --save-dev @babel/plugin-proposal-nullish-coalescing-operator
Конфигурация:
{
"plugins": [
"@babel/plugin-proposal-nullish-coalescing-operator"
]
}
Пример:
const name = value ?? 'default';
Для React используется JSX-транспиляция.
Установка:
npm install --save-dev @babel/preset-react
Конфигурация:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
Пример JSX:
const element = <h1>Hello</h1>;
После Babel:
const element = React.createElement("h1", null, "Hello");
Babel умеет удалять TypeScript-аннотации.
Установка:
npm install --save-dev @babel/preset-typescript
Конфигурация:
{
"presets": [
"@babel/preset-typescript"
]
}
Webpack:
{
test: /\.ts$/,
use: 'babel-loader'
}
Babel:
TypeScript Compiler (tsc):
Часто используется связка:
TypeScript -> Babel -> Webpack
Конфигурация:
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
Такой подход удобен:
Babel поддерживает разные настройки для окружений.
Пример:
{
"env": {
"development": {
"sourceMaps": true
},
"production": {
"comments": false
}
}
}
Запуск:
NODE_ENV=production webpack
Режим диагностики:
{
"presets": [
[
"@babel/preset-env",
{
"debug": true
}
]
]
}
Babel покажет:
Можно отключить отдельные трансформации:
{
"presets": [
[
"@babel/preset-env",
{
"exclude": [
"@babel/plugin-transform-arrow-functions"
]
}
]
]
}
Принудительное включение:
{
"presets": [
[
"@babel/preset-env",
{
"include": [
"@babel/plugin-transform-classes"
]
}
]
]
}
Некоторые преобразования могут выполняться в упрощённом виде.
Пример:
{
"presets": [
[
"@babel/preset-env",
{
"loose": true
}
]
]
}
Преимущества:
Недостаток — возможное отклонение от спецификации ECMAScript.
Для больших проектов:
npm install --save-dev thread-loader
Конфигурация:
{
test: /\.js$/,
use: [
'thread-loader',
'babel-loader'
]
}
thread-loader запускает обработку в отдельных
потоках.
Современная конфигурация обычно включает:
npm install --save-dev webpack webpack-cli babel-loader
Webpack 5:
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'bundle.[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
}
]
}
};
.babelrc:
{
"presets": [
[
"@babel/preset-env",
{
"targets": "> 0.25%, not dead",
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
Причины:
.babelrc;test;exclude;@babel/preset-env.Ошибка:
Unexpected token <
Причина — Babel не умеет обрабатывать JSX.
Решение:
npm install --save-dev @babel/preset-react
Причина:
@babel/core
не установлен.
Решение:
npm install --save-dev @babel/core
Причины:
core-js;regenerator-runtime;useBuiltIns.Основные способы ускорения:
| Метод | Эффект |
|---|---|
cacheDirectory |
ускорение повторной сборки |
exclude: /node_modules/ |
уменьшение объёма обработки |
thread-loader |
параллельная компиляция |
| уменьшение числа плагинов | снижение нагрузки |
точные targets |
меньше трансформаций |
Последовательность обработки:
Исходный файл
↓
babel-loader
↓
Babel presets/plugins
↓
Транспилированный код
↓
Webpack bundle
babel-loader выступает связующим звеном между системой
модульной сборки и системой транспиляции JavaScript-кода.