@rollup/plugin-replace

Плагин @rollup/plugin-replace предназначен для статической замены строковых выражений во время сборки проекта с использованием Rollup. Основная задача заключается в подстановке значений переменных окружения, констант конфигурации и любых текстовых маркеров непосредственно в исходный код до его финальной сборки.

Ключевая особенность подхода — замена выполняется на этапе бандлинга, а не во время выполнения в браузере или Node.js. Это позволяет исключать условные конструкции, связанные с окружением, и формировать специализированные сборки под разные сценарии: production, development, staging.


Принцип работы

Плагин выполняет синтаксически безопасную замену строковых фрагментов в исходных модулях Rollup. В отличие от простого поиска и замены текста, используется анализ AST, что минимизирует риск повреждения кода.

Замена происходит до этапа минификации и оптимизации, что позволяет другим плагинам и Rollup Tree Shaking учитывать уже изменённые значения.


Установка

Плагин подключается как стандартная зависимость разработки:

npm install @rollup/plugin-replace --save-dev

Базовая конфигурация

Минимальная настройка подключается через rollup.config.js:

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

export default {
  input: 'src/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'esm'
  },
  plugins: [
    replace({
      values: {
        __VERSION__: '1.0.0'
      },
      preventAssignment: true
    })
  ]
};

В данном примере все вхождения __VERSION__ в коде будут заменены на строку 1.0.0.


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

values

Объект пар ключ-значение для замены.

replace({
  values: {
    __API_URL__: 'https://api.example.com',
    __MODE__: 'production'
  }
});

Каждый ключ рассматривается как шаблон, который заменяется на соответствующее значение.


preventAssignment

Флаг, предотвращающий замену в местах присваивания, где это может привести к ошибкам.

replace({
  values: {
    DEBUG: 'false'
  },
  preventAssignment: true
});

Без этого параметра возможны ситуации, когда заменяемое значение интерпретируется как часть выражения присваивания, что ломает логику кода.


include и exclude

Позволяют ограничить область применения плагина:

replace({
  values: {
    __ENV__: 'dev'
  },
  include: ['src/**'],
  exclude: ['node_modules/**']
});

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


delimiters

Определяет границы поиска заменяемых токенов:

replace({
  values: {
    API_KEY: '123'
  },
  delimiters: ['', '']
});

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


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

Наиболее распространённый сценарий — подстановка значений из process.env.

replace({
  values: {
    'process.env.NODE_ENV': JSON.stringify('production'),
    'process.env.API_URL': JSON.stringify('https://api.prod.com')
  },
  preventAssignment: true
});

Такой подход позволяет полностью исключить обращения к process.env в итоговом бандле.


Интеграция с process.env через автоматизацию

Часто используется совместно с dotenv:

import replace from '@rollup/plugin-replace';
import dotenv from 'dotenv';

dotenv.config();

export default {
  plugins: [
    replace({
      values: Object.entries(process.env).reduce((acc, [key, value]) => {
        acc[`process.env.${key}`] = JSON.stringify(value);
        return acc;
      }, {}),
      preventAssignment: true
    })
  ]
};

Это позволяет централизованно управлять конфигурацией через .env.


Типичные сценарии применения

Разделение production и development

replace({
  values: {
    __DEV__: 'false',
    __LOG_LEVEL__: '"error"'
  }
});

В коде:

if (__DEV__) {
  console.log('debug');
}

После сборки условие исчезает или упрощается до статического значения.


Feature flags

replace({
  values: {
    __FEATURE_CHAT__: 'true',
    __FEATURE_BETA__: 'false'
  }
});

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


Версионирование

replace({
  values: {
    __BUILD_VERSION__: JSON.stringify('2026.05.30')
  }
});

Используется для отображения версии в UI или логах.


Важные особенности поведения

Статическая природа замены

Плагин не выполняет вычислений. Все значения должны быть известны на этапе сборки. Любая попытка использовать динамические выражения приводит к необходимости предварительной обработки.


Работа с кавычками

При подстановке строк важно явно использовать JSON.stringify, иначе возможно повреждение синтаксиса:

values: {
  __API__: JSON.stringify('https://api.example.com')
}

Порядок выполнения плагинов

@rollup/plugin-replace должен располагаться до плагинов, которые зависят от итогового кода (например, минификаторов или транспилеров), чтобы замены учитывались в дальнейших преобразованиях.


Взаимодействие с другими плагинами Rollup

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

При использовании @rollup/plugin-typescript замены происходят уже после транспиляции TypeScript в JavaScript, что обеспечивает корректную обработку типов и интерфейсов.


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

При подключении @rollup/plugin-terser заменённые константы позволяют улучшить минификацию, поскольку код становится более предсказуемым и статическим.


Распространённые ошибки

Замена без JSON.stringify

values: {
  __API__: 'https://api.example.com'
}

Результат может привести к некорректному JS-коду, если значение вставляется в неподходящий контекст.


Пересечение имён

Если плейсхолдер совпадает с частью другого идентификатора, возможны неожиданные замены:

values: {
  API: 'X'
}

Код:

const API_CLIENT = ...

Может быть частично затронут.


Отсутствие preventAssignment

Без защиты возможны некорректные трансформации выражений, особенно в сложных AST-конструкциях.


Расширенные сценарии использования

Генерация разных сборок из одного кода

const config = {
  values: {
    __TARGET__: JSON.stringify('mobile')
  }
};

Позволяет собирать отдельные версии приложения под разные платформы.


Удаление кода через условные флаги

replace({
  values: {
    __ENABLE_LOGS__: 'false'
  }
});
if (__ENABLE_LOGS__) {
  console.log('log');
}

После сборки блок логирования может быть удалён tree-shaking-ом.


Подмена API endpoints

replace({
  values: {
    __API_BASE__: JSON.stringify('https://staging.api.local')
  }
});

Позволяет переключать окружения без изменения исходного кода.


Производительность и ограничения

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

Основные ограничения:

  • отсутствие runtime-логики
  • невозможность условных вычислений
  • зависимость от статических значений
  • риск конфликтов имён при плохом нейминге плейсхолдеров

Рекомендации по архитектуре использования

  • использовать единый стиль плейсхолдеров (__NAME__)
  • централизовать конфигурацию через отдельный модуль
  • избегать прямого использования process.env в коде без замены
  • применять preventAssignment: true как обязательный параметр
  • группировать значения по окружениям (dev/prod/test)

Пример комплексной конфигурации

import replace from '@rollup/plugin-replace';
import dotenv from 'dotenv';

dotenv.config();

const env = process.env.NODE_ENV || 'development';

export default {
  input: 'src/index.js',
  output: {
    file: `dist/bundle.${env}.js`,
    format: 'esm'
  },
  plugins: [
    replace({
      values: {
        __DEV__: JSON.stringify(env === 'development'),
        __PROD__: JSON.stringify(env === 'production'),
        __API_URL__: JSON.stringify(process.env.API_URL),
        'process.env.NODE_ENV': JSON.stringify(env)
      },
      preventAssignment: true
    })
  ]
};