В процессе сборки JavaScript-приложений bundler анализирует граф зависимостей и объединяет модули в один или несколько выходных файлов. Однако не все зависимости должны попадать в итоговый бандл. Часть модулей может существовать во внешней среде выполнения — предоставляться браузером, CDN, Node.js или отдельной системой загрузки. Такие зависимости называются externals.
Externally подключаемые модули исключаются из процесса бандлинга, а вместо их кода в сборку подставляются обращения к глобальным переменным или импортам, которые будут доступны во время выполнения.
Ключевые свойства external-зависимостей:
Parcel анализирует зависимости на этапе построения графа модулей. Когда модуль помечен как external, резолвер перестаёт обрабатывать его содержимое как часть графа и заменяет его ссылкой.
При этом поведение отличается от обычного exclude в
других сборщиках:
Пример логики:
import React from "react";
Если react объявлен external, Parcel не включит код
React в сборку, а оставит импорт как есть (или преобразует его в формат,
соответствующий целевому окружению).
В Parcel 2 управление внешними зависимостями осуществляется через
поле targets в package.json.
Основная структура:
{
"name": "app",
"version": "1.0.0",
"targets": {
"default": {
"distDir": "dist",
"external": [
"react",
"react-dom"
]
}
}
}
externalimport или
require, в зависимости от режима сборки.В браузере external-зависимости обычно связаны с глобальными переменными, предоставленными через CDN или отдельные скрипты.
Пример сценария:
react как external;window.React.Parcel при этом не подставляет код React в бандл.
Однако важно учитывать, что Parcel сам по себе не «угадывает» глобальные переменные. Связь между модулем и глобальным объектом должна быть обеспечена вручную через HTML или системную интеграцию.
В Node.js externals используются чаще всего для:
fs, path,
crypto);Parcel при сборке под Node может оставлять такие зависимости нетронутыми.
Пример:
{
"targets": {
"node": {
"context": "node",
"external": ["fs", "path"]
}
}
}
Такой подход позволяет:
Parcel предоставляет несколько механизмов управления зависимостями, которые часто путают между собой.
Полное исключение модуля из сборки.
Перенаправление импорта на другой модуль.
Пример:
{
"alias": {
"react": "preact/compat"
}
}
Настройка алгоритма поиска модулей.
Ключевое различие:
Многие библиотеки публикуются с peerDependencies,
предполагая, что зависимости будут предоставлены внешней средой.
Parcel external часто используется для реализации этого поведения.
Пример сценария:
react;react помечается как external.package.json:
{
"peerDependencies": {
"react": "^18.0.0"
},
"targets": {
"default": {
"external": ["react"]
}
}
}
Это предотвращает:
При создании npm-пакетов external играет критическую роль.
Типичная цель:
Пример:
{
"targets": {
"library": {
"context": "browser",
"outputFormat": "esm",
"external": ["react", "react-dom"]
}
}
}
Результат:
External-зависимости полностью исключаются из графа, поэтому:
Это может быть как преимуществом, так и ограничением:
В серверном рендеринге external используется для разделения окружений:
Пример:
window-зависимые модули external на сервере;Dynamic import взаимодействует с external следующим образом:
const mod = await import("analytics-lib");
Если модуль объявлен external:
Это требует согласованной стратегии загрузки ресурсов.
На практике неправильное использование external приводит к типовым проблемам.
Ситуация:
Результат:
ReferenceError: X is not defined.Если external используется в нескольких пакетах без контроля версии:
Иногда external задаётся слишком широко:
"external": ["react*"]
Это приводит к тому, что:
Использование external влияет на производительность в двух направлениях.
<script> теги.Parcel может собирать код в разные форматы:
External ведёт себя по-разному:
import;require;Parcel runtime не загружает external-зависимости автоматически. Это принципиальная модель:
Поэтому external всегда требует внешней координации:
External-зависимости формируют границу между:
Эта граница позволяет:
Parcel реализует этот механизм через декларативную конфигурацию, встроенную в targets, сохраняя единый подход к различным платформам и типам сборок.