Структура проекта и точка входа

Структура проекта при использовании Rollup строится вокруг принципа явного определения входной точки и прозрачного контроля над графом модулей. В отличие от монолитных сборок, где исходный код рассматривается как единое целое, Rollup опирается на модульную модель ES Modules и выстраивает граф зависимостей от указанного entry.

Типичный проект на Rollup минимально включает следующие элементы:

project/
  src/
    index.js
  dist/
  rollup.config.js
  package.json

Ключевым является каталог src, в котором располагается исходный код, и файл конфигурации, определяющий поведение сборщика.

Исходный код и точка входа

Файл src/index.js традиционно выступает входной точкой:

import { sum } from './utils/sum.js';
import { multiply } from './utils/multiply.js';

export function calculate(a, b) {
  return sum(a, b) + multiply(a, b);
}

Rollup начинает построение графа именно с этого файла. Все import становятся ребрами графа зависимостей, а export определяют публичный API модуля.

Конфигурация входной точки

В Rollup входная точка задаётся явно через параметр input:

export default {
  input: 'src/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'esm'
  }
};

Здесь важно, что input не просто строка, а начало обхода графа модулей. Rollup не ищет зависимости автоматически в папках — он строго следует указанному пути.

Относительные и абсолютные входные пути

Допустимы различные формы задания:

input: './src/index.js'

или с использованием Node-резолвинга:

input: require.resolve('./src/index.js')

В больших проектах предпочтение часто отдают абсолютным путям, чтобы исключить неоднозначность при запуске из разных окружений.

Несколько точек входа

Rollup поддерживает мульти-entry конфигурации, что важно для библиотек, предоставляющих несколько независимых API.

Массив входных файлов

export default {
  input: ['src/index.js', 'src/admin.js'],
  output: {
    dir: 'dist',
    format: 'esm'
  }
};

В этом случае каждый вход формирует отдельный chunk.

Объектная форма

Более контролируемый вариант:

export default {
  input: {
    main: 'src/index.js',
    admin: 'src/admin.js'
  },
  output: {
    dir: 'dist',
    format: 'esm'
  }
};

Результат:

dist/
  main.js
  admin.js

Такой подход позволяет явно управлять именами выходных файлов.

Роль точки входа в графе модулей

Внутренне Rollup строит directed graph, где:

  • узлы — модули
  • ребра — импортируемые зависимости

Входная точка является корневым узлом обхода. Пример:

index.js
 ├── utils/sum.js
 ├── utils/multiply.js
 └── constants.js

Rollup анализирует только те модули, которые достижимы из entry. Всё остальное игнорируется, что напрямую связано с tree-shaking.

Форматы вывода и влияние входной точки

Выбор entry напрямую влияет на структуру выходного бандла:

ESM

output: {
  format: 'esm'
}

Каждый входной модуль сохраняет структуру импортов. Entry становится корнем ESM-графа.

IIFE

output: {
  format: 'iife',
  name: 'MyLibrary'
}

Входной файл превращается в точку инициализации IIFE-функции:

var MyLibrary = (function () {
  // содержимое entry и зависимостей
})();

CommonJS

output: {
  format: 'cjs'
}

Entry становится модулем, экспортируемым через module.exports.

Разделение библиотечного и приложенческого entry

В библиотеках часто используют отдельный entry для публичного API:

src/
  index.js        // публичный API
  internal/
    helpers.js
export { calculate } from './core/calculate.js';

В приложениях entry обычно содержит побочные эффекты:

import './styles.css';
import { initApp } from './app/init.js';

initApp();

Dynamic import и влияние на entry

Динамические импорты влияют на граф следующим образом:

export async function loadModule() {
  const mod = await import('./heavy-module.js');
  return mod.run();
}

Rollup разделяет такие модули в отдельные чанки, но они остаются связанными с основным entry через async edge.

preserveModules и сохранение структуры

При необходимости сохранить структуру проекта используется:

export default {
  input: 'src/index.js',
  output: {
    dir: 'dist',
    format: 'esm',
    preserveModules: true
  }
};

В этом режиме entry перестаёт быть точкой объединения, а превращается в корень дерева файлов.

Структура сохраняется:

dist/
  index.js
  utils/
    sum.js
    multiply.js

Entry и code splitting

При нескольких entry Rollup автоматически выполняет дедупликацию зависимостей:

input: {
  app: 'src/app.js',
  admin: 'src/admin.js'
}

Если оба entry используют один модуль:

import { log } from './shared/log.js';

то Rollup выносит его в отдельный shared chunk.

Влияние package.json на входную точку

Хотя Rollup не зависит напрямую от package.json, в библиотечных проектах часто согласуют entry с полями:

{
  "main": "dist/index.cjs",
  "module": "dist/index.js",
  "exports": {
    "import": "./dist/index.js",
    "require": "./dist/index.cjs"
  }
}

Это не влияет на процесс сборки, но определяет потребление результата.

Контроль входной точки через плагины

Некоторые плагины могут модифицировать entry-граф:

  • виртуальные модули (virtual:)
  • условные entry
  • генерация entry на лету

Пример виртуального entry:

import virtual from '@rollup/plugin-virtual';

export default {
  input: 'entry',
  plugins: [
    virtual({
      entry: 'export default 42;'
    })
  ]
};

Здесь entry существует только в памяти.

Множественные уровни entry в монорепозиториях

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

packages/
  core/
    src/index.js
  ui/
    src/index.js

Каждый пакет имеет собственный entry:

input: 'packages/core/src/index.js'

или через отдельные конфиги Rollup для каждого пакета.

Связь entry и оптимизации tree-shaking

Entry определяет границы анализа:

  • недостижимые модули исключаются
  • побочные эффекты учитываются только внутри reachable graph
  • экспортируемые, но не используемые символы удаляются

Чем точнее entry, тем эффективнее tree-shaking.

Ошибки, связанные с entry

Типичные проблемы:

  • указание файла, не содержащего экспортов
  • циклические зависимости от entry
  • включение side-effect модулей без необходимости
  • смешивание CommonJS entry с ESM графом без трансформации

Каждая из этих ситуаций влияет на корректность построения графа и результат сборки.