На протяжении многих лет Webpack оставался стандартом де-факто для сборки JavaScript-приложений. Его гибкость, развитая экосистема и высокая настраиваемость сделали его основой огромного количества проектов. Однако вместе с преимуществами появились и недостатки:
Parcel предлагает альтернативный подход. Основная идея заключается в автоматизации большинства задач, которые в Webpack требуют отдельной настройки.
Ключевые особенности Parcel:
Миграция особенно актуальна для проектов, где конфигурация Webpack постепенно разрослась и стала сложной в сопровождении.
Перед переносом необходимо определить, какие возможности используются в текущем проекте.
Типичная конфигурация Webpack может выглядеть следующим образом:
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
Во время анализа следует обратить внимание на:
entry: './src/index.js'
или
entry: {
app: './src/app.js',
admin: './src/admin.js'
}
Чаще всего встречаются:
Например:
plugins: [
new HtmlWebpackPlugin(),
new MiniCssExtractPlugin()
]
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
new webpack.DefinePlugin({
API_URL: JSON.stringify(process.env.API_URL)
})
optimization: {
splitChunks: {
chunks: 'all'
}
}
Полный список используемых возможностей позволит определить объём будущей миграции.
Для начала необходимо удалить зависимости, относящиеся к Webpack.
Пример списка пакетов:
npm uninstall webpack
npm uninstall webpack-cli
npm uninstall webpack-dev-server
npm uninstall babel-loader
npm uninstall css-loader
npm uninstall style-loader
После этого устанавливается Parcel:
npm install --save-dev parcel
Или:
yarn add --dev parcel
Webpack обычно использует такие сценарии:
{
"scripts": {
"start": "webpack serve",
"build": "webpack --mode production"
}
}
После перехода на Parcel они изменяются следующим образом:
{
"scripts": {
"start": "parcel src/index.html",
"build": "parcel build src/index.html"
}
}
Parcel рассматривает HTML-файл как корневую точку входа приложения.
В Webpack чаще всего используется JavaScript-файл:
entry: './src/index.js'
В Parcel рекомендуется использовать HTML:
<!DOCTYPE html>
<html>
<head>
<title>Application</title>
</head>
<body>
<script type="module" src="./index.js"></script>
</body>
</html>
Запуск сборки:
parcel src/index.html
Parcel самостоятельно обнаружит все зависимости и включит их в итоговый бандл.
В Webpack настройка Babel обычно выглядит так:
{
test: /\.js$/,
loader: 'babel-loader'
}
И сопровождается файлом:
{
"presets": ["@babel/preset-env"]
}
Parcel автоматически обнаруживает Babel-конфигурацию.
Достаточно оставить файл:
{
"presets": ["@babel/preset-env"]
}
или
module.exports = {
presets: ['@babel/preset-env']
};
Дополнительная настройка загрузчиков не требуется.
В Webpack подключение CSS обычно требует нескольких загрузчиков:
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
В Parcel достаточно импортировать файл:
import './styles.css';
После запуска сборки:
parcel src/index.html
стили автоматически попадут в итоговый результат.
В Webpack:
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
В Parcel достаточно установить Sass:
npm install --save-dev sass
Импорт:
import './styles.scss';
Parcel автоматически активирует соответствующий трансформер.
В старых конфигурациях Webpack часто используются:
{
test: /\.(png|jpg|svg)$/i,
loader: 'file-loader'
}
или:
{
test: /\.(png|jpg)$/i,
loader: 'url-loader'
}
В Parcel изображения импортируются напрямую:
import logo from './logo.png';
image.src = logo;
или используются в HTML:
<img src="./logo.png" alt="Logo">
Parcel самостоятельно:
Webpack-конфигурация:
{
test: /\.ts$/,
loader: 'ts-loader'
}
Parcel требует только установки TypeScript:
npm install --save-dev typescript
После этого можно создавать файлы:
const message: string = 'Hello';
Parcel автоматически распознает расширение:
index.ts
и выполнит компиляцию.
Webpack:
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
Parcel не требует отдельного плагина.
Достаточно использовать HTML-файл напрямую:
parcel src/index.html
Все необходимые скрипты будут подключены автоматически.
В Webpack часто используется:
new webpack.DefinePlugin({
API_URL: JSON.stringify(process.env.API_URL)
})
В Parcel переменные доступны напрямую:
API_URL=https://api.example.com
Использование:
console.log(process.env.API_URL);
или в современных версиях:
console.log(process.env.API_URL);
Parcel самостоятельно внедрит значения во время сборки.
Webpack:
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
Parcel использует настройки в файле package.json.
Пример:
{
"alias": {
"@": "./src"
}
}
Импорт:
import Button from '@/components/Button';
Webpack:
{
"scripts": {
"dev": "webpack serve"
}
}
Parcel имеет встроенный сервер разработки:
parcel src/index.html
Поддерживаются:
Дополнительные пакеты устанавливать не требуется.
Webpack:
optimization: {
splitChunks: {
chunks: 'all'
}
}
В Parcel применяется динамический импорт:
const module = await import('./module.js');
При сборке Parcel автоматически создаст отдельный чанк.
Пример:
button.addEventListener('click', async () => {
const editor = await import('./editor.js');
editor.init();
});
В результате модуль будет загружаться только при необходимости.
Webpack:
new Worker(
new URL('./worker.js', import.meta.url)
);
Parcel поддерживает аналогичный синтаксис:
const worker = new Worker(
new URL('./worker.js', import.meta.url)
);
Дополнительная конфигурация отсутствует.
Webpack обычно требует настройки множества точек входа:
entry: {
home: './src/home.js',
admin: './src/admin.js'
}
Parcel позволяет использовать несколько HTML-файлов:
parcel build src/home.html src/admin.html
Структура:
src/
├─ home.html
├─ admin.html
├─ home.js
└─ admin.js
Каждая страница получает собственный набор ресурсов.
Webpack часто содержит большое количество настроек оптимизации:
optimization: {
minimize: true
}
Parcel выполняет автоматически:
Сборка:
parcel build src/index.html
После успешного перехода обычно становятся не нужны:
webpack.config.js
а также многочисленные зависимости:
webpack
webpack-cli
webpack-dev-server
style-loader
css-loader
file-loader
url-loader
mini-css-extract-plugin
html-webpack-plugin
Размер файла package.json заметно сокращается, а процесс
поддержки сборки становится проще.
Некоторые проекты содержат конструкции:
require.context(...)
Parcel их не поддерживает.
Необходимо заменить на стандартные механизмы ECMAScript:
import.meta.glob(...)
или явные импорты.
Иногда бизнес-логика завязана на возможности конкретного loader.
Например:
import template from './template.html';
Следует проверить поддержку аналогичного поведения в Parcel либо заменить архитектурное решение.
Если проект использует собственные плагины:
class CustomPlugin {
apply(compiler) {}
}
прямого аналога может не существовать.
В подобных случаях используются:
В больших монорепозиториях необходимо проверить:
Подходит для небольших проектов.
Этапы:
Подходит для крупных систем.
Схема:
Webpack
↓
Экспериментальная ветка
↓
Parcel
↓
Тестирование
↓
Основная ветка
Такой подход позволяет постепенно устранять несовместимости.
На определённом этапе могут существовать обе системы сборки:
{
"scripts": {
"webpack-build": "webpack",
"parcel-build": "parcel build src/index.html"
}
}
После полного тестирования старая конфигурация удаляется.
Структура проекта с Webpack:
project/
├─ src/
├─ webpack.config.js
├─ .babelrc
├─ package.json
└─ node_modules/
После перехода на Parcel:
project/
├─ src/
├─ .babelrc
├─ package.json
└─ node_modules/
В большинстве случаев исчезает необходимость поддерживать крупный конфигурационный файл, а процесс сборки становится более декларативным и ориентированным на структуру самого приложения, а не на описание инфраструктуры сборщика.