Настройка node target

В Parcel система целей сборки (targets) определяет, под какую среду выполняется итоговый бандл: браузер, Node.js, Electron и другие окружения. При выборе Node.js target сборщик перестраивает граф модулей, формат вывода и поведение зависимостей так, чтобы код корректно выполнялся в серверной среде без браузерных API.

Node target в Parcel ориентирован на создание серверных приложений, CLI-утилит и библиотек, которые выполняются в среде Node.js. Его ключевая задача — исключить браузерные предположения из сборки и адаптировать код под Node runtime.


Базовая концепция targets в Parcel

Parcel использует декларативную модель конфигурации, где цели сборки описываются через package.json или через CLI.

Каждый target определяет:

  • формат выходного кода (CommonJS или ESM)
  • окружение выполнения (browser / node / electron)
  • уровень оптимизации (minify, scope hoisting)
  • поведение с зависимостями (external или bundled)
  • совместимость с Node.js встроенными модулями

Структура targets в package.json:

{
  "targets": {
    "node": {
      "context": "node",
      "engines": {
        "node": ">=18"
      },
      "outputFormat": "commonjs",
      "distDir": "dist/node"
    }
  }
}

Контекст выполнения и его влияние

Ключевой параметр Node target — context: "node". Он переключает внутреннюю логику Parcel:

1. Исключение браузерных полифилов

В browser target Parcel может автоматически добавлять полифилы для process, Buffer, path, crypto. В node target это поведение отключается.

2. Использование встроенных Node API

Модули fs, path, stream, url, crypto остаются нативными и не подменяются браузерными заглушками.

3. Упрощение графа зависимостей

Parcel не пытается адаптировать код под DOM-окружение, что сокращает количество трансформаций.


Форматы вывода: CommonJS и ESM

Node target может генерировать два основных формата:

CommonJS

"outputFormat": "commonjs"

Используется для максимальной совместимости со старыми версиями Node.js и большинством npm-пакетов.

Пример результата:

const fs = require("fs");

module.exports = function readFile(path) {
  return fs.readFileSync(path, "utf8");
};

ES Modules

"outputFormat": "module"

Подходит для современных версий Node.js с поддержкой ESM.

import fs from "fs";

export function readFile(path) {
  return fs.readFileSync(path, "utf8");
}

Parcel автоматически адаптирует расширения и синтаксис под выбранный формат.


Настройка через CLI

Node target можно задать без конфигурационного файла:

parcel build src/index.js --target node

Дополнительные параметры:

parcel build src/index.js \
  --target node \
  --dist-dir dist/node \
  --no-minify

CLI target переопределяет настройки из package.json, если конфликтует.


Разделение сборок: browser и node одновременно

Parcel поддерживает мульти-target сборку, что особенно важно для универсальных библиотек.

Пример конфигурации:

{
  "targets": {
    "browser": {
      "context": "browser",
      "outputFormat": "esmodule",
      "distDir": "dist/browser"
    },
    "node": {
      "context": "node",
      "outputFormat": "commonjs",
      "distDir": "dist/node"
    }
  }
}

Структура входа:

export function sharedLogic() {
  return "core";
}

Parcel создаёт два независимых бандла, оптимизированных под разные среды.


Обработка встроенных модулей Node.js

В node target Parcel ведёт себя иначе по отношению к встроенным модулям:

Не бандлит core modules

Модули:

  • fs
  • path
  • os
  • net
  • http

остаются внешними зависимостями.

import path from "path";
import fs from "fs";

В итоговом бандле они сохраняются как require("fs").


Работа с node_modules

Parcel в Node target может работать в двух режимах:

1. Инлайнинг зависимостей

Зависимости включаются в бандл, если они ESM или не отмечены как external.

2. External режим

При некоторых конфигурациях зависимости остаются внешними:

"targets": {
  "node": {
    "external": ["express"]
  }
}

Это используется для серверных приложений, где node_modules доступны на диске.


Поддержка package.json exports

Node target учитывает поле exports:

{
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  }
}

Parcel корректно выбирает entrypoint в зависимости от outputFormat и context.


Tree shaking в Node target

Tree shaking в Node target работает иначе, чем в браузерном:

  • меньше агрессивная удаляемость кода
  • сохранение динамических require
  • осторожная обработка side effects

Пример:

export function used() {
  return "used";
}

export function unused() {
  return "unused";
}

Если unused не импортируется, Parcel удалит её, но только при отсутствии sideEffects в package.json.


Side effects и их влияние

Node target учитывает:

{
  "sideEffects": false
}

Это позволяет безопасно удалять неиспользуемые модули.

Если sideEffects: true, Parcel сохраняет выполнение всех импортов, даже если они не используются напрямую.


Работа с переменными окружения

Node target активно использует process.env:

if (process.env.NODE_ENV === "production") {
  console.log("prod mode");
}

Parcel выполняет compile-time replacement:

process.env.NODE_ENV → "production"

Это позволяет удалять условные ветки в продакшене.


Source maps в Node target

Parcel генерирует source maps для Node сборок:

{
  "sourceMaps": true
}

Это критично для:

  • серверной отладки
  • production tracing
  • ошибок в async stack traces

Node.js поддерживает source maps нативно, начиная с современных версий, что делает интеграцию прозрачной.


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

Node target поддерживает:

const module = await import("./dynamic.js");

Parcel преобразует это в:

  • отдельный chunk
  • корректный Node ESM loader (или runtime require fallback в CJS)

Работа с __dirname и __filename

В ESM режиме Node target Parcel эмулирует:

import { fileURLToPath } from "url";
import { dirname } from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

В CommonJS режиме они остаются нативными.


Оптимизация для серверных приложений

Node target включает специфические оптимизации:

1. Удаление DOM-связанных полифилов

Нет загрузки document, window, navigator.

2. Упрощённый runtime

Меньше bootstrap-кода по сравнению с browser target.

3. Оптимизация require-графа

Быстрее разрешение модулей за счёт Node resolution algorithm.


Совместимость с TypeScript

Node target корректно работает с TypeScript входами:

{
  "extends": "@parcel/config-default",
  "targets": {
    "node": {
      "context": "node"
    }
  }
}

Parcel выполняет:

  • transpile TS → JS
  • type stripping без typecheck (если не включён отдельный процесс)
  • сохранение module resolution под Node

Монорепозитории и Node target

В монорепо структурах Node target часто используется для:

  • серверных пакетов
  • shared utilities
  • CLI инструментов

Parcel корректно обрабатывает workspace зависимости, избегая дублирования зависимостей в бандле.


Частые архитектурные сценарии

CLI приложение

  • context: node
  • outputFormat: commonjs
  • external: true для всех dependencies

API сервер

  • context: node
  • частичный bundling
  • внешние зависимости: express, fastify

библиотека для npm

  • dual build: node + browser
  • строгий tree shaking
  • экспорт через exports

Ошибки конфигурации Node target

1. Смешивание browser и node API

window.fetch()

в node target приведёт к runtime error без polyfill.

2. Неправильный outputFormat

Использование module в старых версиях Node без ESM поддержки вызывает ошибку загрузки.

3. External неучтённые зависимости

Если не указать external для тяжёлых библиотек, bundle может стать избыточным.


Поведение резолвинга модулей

Node target следует Node resolution algorithm:

  • проверка локальных файлов
  • поиск в node_modules
  • учёт package.json exports/imports
  • поддержка conditional exports

Parcel не переопределяет эту модель, а расширяет её оптимизациями сборки.