Инициализация плагина в Parcel строится вокруг декларативного описания расширения через конфигурацию и последующего подключения к жизненному циклу сборщика. В основе лежит модульная архитектура, где каждый плагин представляет собой набор функций, регистрируемых в соответствующих точках пайплайна обработки модулей.
Система плагинов в Parcel организована вокруг нескольких ключевых типов расширений:
Инициализация любого плагина начинается с регистрации его типа и привязки к соответствующим хукам сборочного процесса. Parcel использует ленивую модель загрузки, при которой плагин инициализируется только при необходимости, что снижает накладные расходы.
Плагин в Parcel представляет собой JavaScript-модуль, который экспортирует объект с методами, соответствующими жизненному циклу.
export default {
resolve({ dependency, options }) {
return {
filePath: null
};
},
load({ filePath }) {
return null;
},
transform({ asset }) {
return [asset];
}
};
Каждый метод является точкой инициализации логики, связанной с конкретной стадией обработки ресурсов. При загрузке Parcel регистрирует эти методы в внутреннем планировщике задач.
Инициализация плагина невозможна без объявления в конфигурационном
файле .parcelrc. Этот файл определяет пайплайн плагинов и
порядок их выполнения.
{
"extends": "@parcel/config-default",
"transformers": {
"*.txt": ["parcel-transformer-custom"]
},
"resolvers": ["parcel-resolver-custom"]
}
При запуске сборки Parcel считывает .parcelrc, формирует
граф плагинов и выполняет их инициализацию в соответствии с типами
ресурсов.
Важно, что порядок объявления влияет на цепочку обработки: каждый следующий плагин получает результат предыдущего, если не происходит прерывания цепочки.
Инициализация плагина происходит в несколько этапов:
.parcelrcParcel использует отложенную загрузку: модуль плагина импортируется только при первом обращении к соответствующему типу ресурса.
import myPlugin from 'parcel-plugin-example';
// Parcel выполняет регистрацию функций без немедленного вызова логики
Каждый плагин получает контекст исполнения, который содержит служебные API Parcel. Контекст передаётся при вызове функций плагина, а не при его создании, что позволяет избегать глобального состояния.
export default {
transform({ asset, options, logger }) {
logger.info({
message: 'Transform started'
});
asset.setCode(asset.getCode().toUpperCase());
return [asset];
}
};
Параметр options формируется на этапе инициализации
сборщика и содержит объединённую конфигурацию проекта и плагинов.
Parcel поддерживает автоматическую регистрацию зависимостей внутри плагинов. При инициализации анализируется импортируемый граф модулей, что позволяет включать дополнительные runtime-зависимости без ручной настройки.
export default {
load() {
const helper = require('./helper');
return helper.getData();
}
};
Такие зависимости попадают в общий граф и обрабатываются стандартным механизмом Parcel.
Transformer-плагины являются наиболее часто используемым типом
расширений. Их инициализация происходит при совпадении паттерна файла с
правилом в .parcelrc.
{
"transformers": {
"*.css": ["parcel-transformer-css"]
}
}
После сопоставления расширения файла с правилом Parcel:
asset с метаданнымиexport default {
async transform({ asset }) {
const code = await asset.getCode();
asset.setCode(`/* processed */\n${code}`);
return [asset];
}
};
Инициализация происходит один раз на процесс сборки, после чего экземпляр плагина переиспользуется.
Resolver-плагины инициализируются на самой ранней стадии, до построения графа зависимостей. Их задача — определить физическое расположение модулей.
export default {
resolve({ dependency, options }) {
if (dependency.specifier === 'special-module') {
return {
filePath: '/src/special/index.js'
};
}
}
};
Инициализация resolver-плагина критична, поскольку ошибки на этом этапе блокируют построение графа модулей.
Parcel позволяет передавать конфигурационные параметры плагина через
.parcelrc или через опции сборщика.
{
"transformers": {
"*.md": [
"parcel-transformer-markdown",
{
"highlight": true
}
]
}
}
Плагин получает эти данные через объект options при
каждом вызове метода.
export default {
transform({ asset, options }) {
if (options.highlight) {
// дополнительная обработка
}
return [asset];
}
};
Parcel не создаёт новый экземпляр плагина для каждого файла. Вместо этого используется один загруженный модуль, а инициализация сводится к регистрации функций.
Повторная инициализация возможна только при:
.parcelrcВ остальных случаях используется уже загруженный контекст.
Некоторые плагины требуют асинхронной подготовки, например загрузки внешних конфигураций или инициализации SDK. Parcel допускает асинхронные хуки.
let cache;
export default {
async initialize() {
cache = await fetch('https://example.com/config').then(r => r.json());
},
transform({ asset }) {
if (cache?.enabled) {
asset.setCode(asset.getCode() + '\n// enabled');
}
return [asset];
}
};
Хотя метод initialize не является обязательным
стандартом всех плагинов, он часто используется как соглашение внутри
экосистемы.
Parcel активно использует кэширование, что влияет на поведение плагинов при инициализации. Плагин может быть загружен один раз и использован многократно в рамках инкрементальной сборки.
Кэшируются:
Это означает, что логика инициализации должна быть детерминированной и не зависеть от внешнего изменяемого состояния без явного контроля.
Ошибки, возникающие на этапе инициализации плагина, разделяются на несколько категорий:
.parcelrcParcel прекращает выполнение соответствующей стадии сборки при фатальных ошибках resolver- или transformer-плагинов, но может продолжить работу в degraded-режиме для reporter-плагинов.
Инициализация плагина зависит от версии Parcel API. Несовместимость может приводить к тому, что плагин импортируется, но его хуки не регистрируются.
export default function (api) {
api.transform(/* ... */);
}
Такой стиль используется в более старых или экспериментальных реализациях плагинов и требует проверки версии окружения перед инициализацией логики.