Часто теряемые функции и их эквиваленты в Parcel

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

Parcel придерживается концепции zero-configuration, поэтому многие настройки, которые раньше требовали десятков строк конфигурации, работают автоматически. Именно это и становится причиной путаницы: функция существует, но её больше не нужно явно включать.


Отсутствие файла конфигурации сборщика

Что обычно ищут

После опыта работы с Webpack многие ожидают увидеть файл:

webpack.config.js

или аналогичную централизованную конфигурацию.

Эквивалент в Parcel

Parcel в большинстве случаев не требует отдельного конфигурационного файла.

Вместо этого используются:

  • package.json
  • .parcelrc (при необходимости расширения поведения)
  • настройки Babel, PostCSS, TypeScript и других инструментов в их собственных файлах конфигурации

Например:

{
  "source": "src/index.html"
}

Запуск:

parcel build

Уже достаточен для полноценной сборки проекта.

Когда всё же нужен .parcelrc

Если необходимо изменить конвейер обработки ресурсов:

{
  "extends": "@parcel/config-default",
  "transformers": {
    "*.md": ["@parcel/transformer-raw"]
  }
}

Файл .parcelrc становится аналогом сложных настроек Webpack.


Отсутствие Loaders

Что обычно теряется

В Webpack практически любой тип файла подключается через Loader:

module: {
  rules: [
    {
      test: /\.css$/,
      use: ['style-loader', 'css-loader']
    }
  ]
}

Эквивалент в Parcel

Parcel использует систему Transformers.

Большинство популярных типов файлов уже поддерживаются:

  • CSS
  • SCSS
  • Less
  • TypeScript
  • JSX
  • TSX
  • изображения
  • SVG
  • JSON
  • TOML
  • YAML

Пример импорта:

import './styles.scss';

Parcel автоматически:

  1. Найдёт нужный трансформер.
  2. Выполнит компиляцию.
  3. Подключит результат в сборку.

Никаких дополнительных правил не требуется.

Пользовательские трансформеры

Вместо Loader используется Transformer:

{
  "transformers": {
    "*.txt": ["@parcel/transformer-raw"]
  }
}

Отсутствие Plugins в привычном виде

Что обычно ищут

Webpack активно использует плагины:

plugins: [
  new HtmlWebpackPlugin(),
  new CopyWebpackPlugin()
]

Эквивалент в Parcel

Parcel использует специализированную архитектуру:

  • Transformers
  • Bundlers
  • Optimizers
  • Namers
  • Packagers
  • Reporters
  • Resolvers

Каждая часть отвечает только за свою задачу.

Например:

Webpack Plugin Parcel-аналог
HtmlWebpackPlugin встроен
MiniCssExtractPlugin встроен
TerserPlugin встроен
CopyPlugin встроенная обработка ресурсов

Собственные плагины

Вместо универсального Plugin API создаются специализированные расширения:

const { Optimizer } = require('@parcel/plugin');

module.exports = new Optimizer({
  async optimize({ bundle, contents }) {
    return {
      contents
    };
  }
});

Отсутствие HtmlWebpackPlugin

Что обычно теряется

В Webpack HTML-файл обычно генерируется через:

new HtmlWebpackPlugin()

Эквивалент в Parcel

HTML является полноценной точкой входа.

Файл:

<!DOCTYPE html>
<html>
<head>
  <script type="module" src="./app.js"></script>
</head>
</html>

Запуск:

parcel index.html

Parcel автоматически:

  • обнаружит зависимости;
  • соберёт JavaScript;
  • соберёт CSS;
  • вставит корректные пути;
  • создаст production-версию.

Дополнительные плагины не нужны.


Отсутствие CopyWebpackPlugin

Что обычно ищут

Копирование ресурсов:

new CopyWebpackPlugin({
  patterns: [
    { from: 'public' }
  ]
})

Эквивалент в Parcel

Статические ресурсы могут импортироваться напрямую.

Например:

import logo from './assets/logo.png';

или использоваться в HTML:

<img src="./assets/logo.png">

Parcel самостоятельно:

  • перенесёт файл;
  • создаст хэш;
  • обновит путь.

Папка public

Если требуется простое копирование файлов без обработки:

{
  "staticFiles": {
    "staticPath": "public"
  }
}

или использование дополнительных пакетов для статического контента.


Отсутствие css-loader и style-loader

Что обычно теряется

Конфигурация Webpack:

{
  test: /\.css$/,
  use: [
    'style-loader',
    'css-loader'
  ]
}

Эквивалент в Parcel

Обычный импорт:

import './style.css';

Parcel автоматически:

  • анализирует зависимости;
  • собирает CSS;
  • создаёт отдельные CSS-бандлы;
  • подключает стили.

Никакие Loader не требуются.


Отсутствие file-loader

Что обычно ищут

{
  test: /\.(png|jpg)$/i,
  use: ['file-loader']
}

Эквивалент в Parcel

Любой ресурс импортируется напрямую:

import image from './photo.jpg';

После сборки:

console.log(image);

выведет путь к итоговому файлу:

/photo.83f2a1d.jpg

Отсутствие url-loader

Что обычно ищут

Встраивание небольших файлов через Data URI:

url-loader

Эквивалент в Parcel

Parcel автоматически принимает решение о встраивании ресурсов.

Для маленьких файлов возможно создание:

data:image/png;base64,...

Для больших — отдельного файла.

Ручная настройка обычно не требуется.


Отсутствие MiniCssExtractPlugin

Что обычно теряется

В Webpack:

new MiniCssExtractPlugin()

используется для выделения CSS в отдельные файлы.

Эквивалент в Parcel

Parcel делает это автоматически при production-сборке.

Команда:

parcel build src/index.html

создаст:

index.js
index.css

без дополнительной конфигурации.


Отсутствие TerserPlugin

Что обычно ищут

Минификация Jav * aScript:

new TerserPlugin()

Эквивалент в Parcel

При production-сборке минификация выполняется автоматически:

parcel build

Parcel:

  • удаляет лишние пробелы;
  • сокращает код;
  • выполняет оптимизации;
  • уменьшает размер бандла.

Отсутствие Babel Loader

Что обычно теряется

В Webpack:

{
  test: /\.js$/,
  loader: 'babel-loader'
}

Эквивалент в Parcel

Parcel автоматически обнаруживает конфигурацию Babel.

Например:

{
  "presets": ["@babel/preset-env"]
}

Файл:

.babelrc

или:

{
  "babel": {
    "presets": ["@babel/preset-env"]
  }
}

в package.json.

Parcel самостоятельно подключает Babel при необходимости.


Отсутствие DefinePlugin

Что обычно ищут

В Webpack:

new DefinePlugin({
  API_URL: JSON.stringify('https://api.site.com')
})

Эквивалент в Parcel

Использование переменных окружения.

Файл:

.env
API_URL=https://api.site.com

Использование:

console.log(process.env.API_URL);

или:

console.log(import.meta.env.API_URL);

в зависимости от версии и конфигурации проекта.


Отсутствие alias в конфигурации

Что обычно ищут

В Webpack:

resolve: {
  alias: {
    "@": "./src"
  }
}

Эквивалент в Parcel

Псевдонимы настраиваются через package.json.

{
  "alias": {
    "@": "./src"
  }
}

Использование:

import Button from '@/components/Button';

Отсутствие Dev Server в привычном понимании

Что обычно теряется

Настройки:

devServer: {
  hot: true,
  port: 3000
}

Эквивалент в Parcel

Сервер запускается автоматически:

parcel src/index.html

По умолчанию доступны:

  • локальный сервер;
  • автоматическое обновление;
  • отслеживание изменений;
  • HMR;
  • пересборка ресурсов.

Изменение порта:

parcel src/index.html --port 3000

Отсутствие Hot Module Replacement настройки

Что обычно ищут

В Webpack HMR требует отдельной настройки.

Эквивалент в Parcel

HMR встроен.

Файл:

export const version = 1;

После изменения модуль обновляется без полной перезагрузки страницы.

При необходимости можно использовать API:

if (module.hot) {
  module.hot.accept();
}

Хотя в большинстве проектов даже это не требуется.


Отсутствие SplitChunks

Что обычно теряется

Webpack:

optimization: {
  splitChunks: {
    chunks: 'all'
  }
}

Эквивалент в Parcel

Parcel автоматически анализирует граф зависимостей.

Если код используется несколькими точками входа:

import './shared.js';

Parcel создаст общий бандл самостоятельно.

Динамический импорт

const module = await import('./admin.js');

создаёт отдельный chunk автоматически.


Отсутствие Asset Modules

Что обычно ищут

В новых версиях Webpack:

type: 'asset/resource'

или

type: 'asset/inline'

Эквивалент в Parcel

Любой ресурс является частью графа зависимостей.

Пример:

import pdf from './manual.pdf';
import icon from './icon.svg';
import image from './image.png';

Parcel самостоятельно выбирает способ обработки.


Отсутствие ручной настройки Tree Shaking

Что обычно теряется

В Webpack Tree Shaking часто требует специальных настроек.

Эквивалент в Parcel

Tree Shaking встроен по умолчанию.

Исходный код:

export function used() {}
export function unused() {}

Импорт:

import { used } from './utils';

В production-бандл попадёт только используемая функция.


Отсутствие ручной настройки Source Maps

Что обычно ищут

devtool: 'source-map'

Эквивалент в Parcel

Source Maps генерируются автоматически.

Режим разработки:

parcel src/index.html

включает карты исходников по умолчанию.

Для production доступны дополнительные параметры:

parcel build --no-source-maps

Сводная таблица соответствий

Возможность Webpack Эквивалент в Parcel
webpack.config.js Обычно не нужен
Loader Transformer
Plugin Специализированные расширения Parcel
HtmlWebpackPlugin Встроенная работа с HTML
CopyWebpackPlugin Автоматическая обработка ресурсов
file-loader Импорт файлов
url-loader Автоматическое встраивание
css-loader Встроенная поддержка CSS
style-loader Встроенное подключение стилей
MiniCssExtractPlugin Автоматическое выделение CSS
TerserPlugin Встроенная минификация
babel-loader Автоматическое обнаружение Babel
DefinePlugin Переменные окружения
alias Поле alias в package.json
devServer Встроенный сервер разработки
HMR Встроенный HMR
SplitChunks Автоматическое разделение кода
Asset Modules Встроенная система ресурсов
Tree Shaking Встроенный механизм
Source Maps Генерируются автоматически

Главная особенность Parcel заключается в том, что большинство функций, которые в других сборщиках воспринимаются как отдельные плагины, загрузчики или секции конфигурации, представлены встроенными механизмами. Поэтому при миграции многие возможности кажутся отсутствующими, хотя фактически они уже активированы и работают без дополнительной настройки.