Skip to content

bundle.config ​

Конфигурация сборки расширения. Создайте bundle.config.ts в директории расширения:

ts
export default {
  input: './src/my.extension.ts',
  output: {
    js: './dist/my.extension.bundle.js',
    css: './dist/my.extension.bundle.css',
  },
  namespace: 'BX.MyExtension',
};

Также поддерживается JavaScript-конфигурация (bundle.config.js).

Параметры ​

ПараметрТипОписание
inputstringФайл точки входа (.ts, .js или .css)
outputstring | {js?, css?}Путь к выходным бандлам
namespacestringГлобальное пространство имён для экспортов
concat{js?: string[], css?: string[]}Конкатенация файлов в указанном порядке
targetsstring | string[]Целевые браузеры для транспиляции
sourceMapsbooleanГенерация source maps
minificationboolean | objectНастройки минификации Terser
treeshakeboolean | string | objectУдаление неиспользуемого кода. Принимает boolean, пресет Rollup ('smallest', 'safest', 'recommended') или объект TreeshakingOptions (по умолчанию: true)
pluginsPlugin[]Кастомные Rollup-плагины
resolveNodeModulesbooleanРезолв зависимостей из node_modules
babelbooleanВключение/отключение Babel-транспиляции (по умолчанию: true)
standaloneboolean | objectАвтономная сборка с инлайном зависимостей
protectedbooleanЗащита от пересборки
rebuildstring[]Пересборка зависимых расширений
inlinestring[]Встраивание используемого кода других расширений в бандл
transformClassesboolean | string[]Транспиляция классов — все (true) или по именам
emitDeclarationbooleanГенерация .d.ts с namespace-декларациями (по умолчанию: true)
safeNamespacesbooleanБезопасные обращения к неймспейсам зависимостей через optional chaining
bannerstring | {top?, bottom?}Комментарий в начале и/или в конце JS-бандла
cssImagesobjectОбработка изображений в CSS
baselinebooleanПроверка доступности веб-фич при сборке (по умолчанию: true)

CSS-only расширения ​

Если расширение содержит только стили без JavaScript-логики, можно указать CSS-файл как точку входа:

ts
export default {
  input: './src/style.css',
  output: {
    css: './dist/my.extension.bundle.css',
  },
};

При CSS-only сборке:

  • JS-бандл не создаётся
  • В output достаточно указать только css
  • Не нужен файл-обёртка index.ts с импортом стилей

Обработка изображений в CSS ​

Параметр cssImages управляет обработкой изображений, используемых в CSS через url().

По умолчанию изображения до 14 КБ инлайнятся в CSS как base64 (SVG оптимизируются через SVGO). Изображения большего размера копируются в выходную директорию с относительными путями.

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  cssImages: {
    type: 'copy',
  },
};

Параметры cssImages ​

ПараметрТипПо умолчаниюОписание
type'inline' | 'copy''inline'inline — инлайн мелких файлов (base64/SVG), copy — копирование всех файлов
maxSizenumber14Порог в КБ для инлайна (только при type: 'inline')
outputstring—Директория для скопированных файлов
absolutePathsbooleanfalseАбсолютные пути к изображениям вместо относительных
excludestring[][]Glob-маски изображений, которые никогда не инлайнятся (пути от корня расширения)

Управление инлайном отдельных изображений ​

Чтобы изображение не инлайнилось, а копировалось в выходную директорию, добавьте к URL метку ?no-inline. Метка ?inline, наоборот, инлайнит изображение независимо от maxSize, exclude и type: 'copy':

css
.photo {
  /* Скопируется, даже если меньше maxSize */
  background-image: url('./images/photo.png?no-inline');
}

.logo {
  /* Заинлайнится, даже если больше maxSize */
  background-image: url('./images/logo.svg?inline');
}

Метка удаляется из итогового URL, остальные query-параметры сохраняются: url('./images/icon.svg?v=2&no-inline') превратится в url("images/icon.svg?v=2").

Чтобы исключить сразу группу файлов, перечислите маски в exclude:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  cssImages: {
    exclude: ['./src/images/photos/**', '**/*.gif'],
  },
};

SVG со ссылкой на фрагмент (url('./images/sprite.svg#icon')) не инлайнится: фрагмент указывает на часть файла и потерялся бы при встраивании. Такой файл копируется, фрагмент в URL сохраняется.

Порядок приоритетов: метка в URL → exclude → фрагмент SVG → maxSize и type.

Абсолютные пути ​

При absolutePaths: true chef автоматически вычисляет публичный путь расширения и подставляет абсолютные URL в CSS:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  cssImages: {
    absolutePaths: true,
  },
};

Результат в CSS:

css
/* Вместо */
.icon { background: url(./images/icon.png); }

/* Будет */
.icon { background: url(/bitrix/js/ui/buttons/dist/images/icon.png); }

Публичный путь определяется автоматически на основе расположения расширения (/bitrix/js/... для исходников, /local/js/... для проектов).

Плагины ​

Параметр plugins принимает массив Rollup-совместимых плагинов. Плагины добавляются в конец цепочки сборки, после встроенных плагинов Chef.

Установка ​

Установите нужный плагин в директории расширения:

bash
cd /path/to/my.extension
npm install @rollup/plugin-alias

Использование ​

ts
import alias from '@rollup/plugin-alias';
import { resolve } from 'node:path';

export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My',
  plugins: [
    alias({
      entries: [
        { find: '@utils', replacement: resolve(import.meta.dirname, 'src/utils') },
      ],
    }),
  ],
};

Несколько плагинов ​

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

export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My',
  plugins: [
    alias({
      entries: [
        { find: '@utils', replacement: './src/utils' },
      ],
    }),
    replace({
      __VERSION__: JSON.stringify('1.0.0'),
      preventAssignment: true,
    }),
  ],
};

Резолв node_modules ​

Параметр resolveNodeModules включает резолв зависимостей из node_modules. По умолчанию Chef считает все npm-зависимости внешними — они не попадают в бандл.

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My',
  resolveNodeModules: true,
};

При включении:

  1. Установите зависимости: npm install в директории расширения
  2. Зависимости из node_modules будут инлайниться в бандл
  3. Размер бандла увеличится, но расширение станет автономным от npm

TIP

Если нужна полная автономность от Bitrix-зависимостей, используйте standalone режим.

Встраивание расширений ​

По умолчанию импорт другого Bitrix-расширения остаётся внешней зависимостью: в бандл он не попадает, расширение добавляется в rel в config.php и загружается на страницу целиком. Параметр inline перечисляет расширения, код которых нужно встроить в бандл:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My',
  inline: ['ui.icon-set.api.core', 'ui.bbcode.*'],
};
  • В бандл попадает только тот код, который реально импортирован и используется, — остальное удаляется при сборке.
  • Встроенные расширения не попадают в rel. Их собственные зависимости остаются внешними и попадают в rel, если сами не перечислены в inline.
  • CSS, который импортируют исходники встроенного расширения, попадает в CSS-бандл.
  • Имена принимают глоб-паттерны: * — один сегмент имени, ** — любое число сегментов.
  • Исходники встроенного расширения могут быть на TypeScript, JavaScript или Flow — независимо от языка текущего расширения.
  • Тестовый бандл chef test встраивает те же расширения.

Ограничения:

  • Встроить можно только расширение с bundle.config и исходниками. Если исходников нет, сборка завершается ошибкой CF1016.
  • Встроенный код — отдельная копия. Если то же расширение загружается на страницу через rel другой зависимости, его код выполнится дважды: классы из разных копий не проходят проверку instanceof, а состояние уровня модуля (реестры, подписки на события, кеши) не общее. Chef предупреждает об этом кодом CF1017.
  • Встроенный код не регистрируется в неймспейсе исходного расширения: например, после встраивания ui.icon-set.api.core объект BX.UI.IconSet им не заполняется.
  • Удаляется только код, до которого не дотягиваются используемые функции. Если используемый класс обращается ко всему модулю (например, перебирает все наборы данных), в бандл попадёт весь модуль.
  • Изменения во встроенном расширении попадают в бандл только после пересборки текущего. Чтобы пересобирать его автоматически, добавьте текущее расширение в rebuild встроенного.
  • В standalone-режиме встраиваются все зависимости, inline в нём не нужен.

Standalone ​

Автономная сборка, при которой все Bitrix-зависимости и npm-пакеты инлайнятся в один бандл. Подробнее о режиме — в разделе Standalone-сборка.

Простая форма:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  standalone: true,
};

С переопределением зависимостей через remap:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  standalone: {
    remap: {
      // Битрикс-расширение → другое Битрикс-расширение
      'ui.type-only-dep': 'ui.forms',

      // Битрикс-расширение → npm-пакет
      'ui.lexical.core': { npm: 'lexical', from: 'ui.lexical' },

      // Глоб-паттерн
      'ui.lexical.*': { npm: '@lexical/*', from: 'ui.lexical' },
    },
  },
};

Ключ — имя Bitrix-расширения (или глоб-паттерн), значение:

  • string — имя другого Bitrix-расширения, код которого нужно подставить
  • { npm, from } — npm-пакет (npm) из node_modules указанного расширения (from)

В глоб-паттернах * заменяется на совпавшую часть имени. Например, 'ui.lexical.*': { npm: '@lexical/*', from: 'ui.lexical' } превращает ui.lexical.rich-text в @lexical/rich-text.

Отключение Babel ​

Параметр babel позволяет отключить Babel-транспиляцию. Это полезно, когда код уже предварительно собран и повторная обработка Babel не нужна.

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My',
  babel: false,
};

WARNING

Без Babel код не будет транспилирован под целевые браузеры. Используйте эту опцию, только если уверены, что входной код уже совместим с нужными браузерами.

Транспиляция классов ​

Параметр transformClasses включает транспиляцию ES-классов в функции через Babel. Это необходимо для совместимости с устаревшим кодом, который расширяет классы через BX.merge, Object.assign или другие паттерны, несовместимые с нативными классами.

Транспилировать все классы:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My',
  transformClasses: true,
};

Транспилировать только указанные классы:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My',
  transformClasses: ['EventEmitter', 'BaseEvent'],
};

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

Декларации типов ​

При сборке TypeScript-расширений Chef автоматически генерирует файл .d.ts с ambient namespace-декларациями рядом с бандлом. Это позволяет IDE предоставлять подсказки при обращении по неймспейсу, например new BX.UI.Bbcode.App().

dist/
├── app.bundle.js      # Скомпилированный бандл (без комментариев)
└── app.bundle.d.ts    # Декларации типов с JSDoc

JSDoc-комментарии из исходников сохраняются в .d.ts для подсказок IDE, но удаляются из рантайм-бандла для уменьшения размера.

Генерация работает только для TypeScript-расширений с указанным namespace (отличным от window).

Для отключения:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My',
  emitDeclaration: false,
};

Безопасные неймспейсы ​

По умолчанию, если расширение зависит от другого расширения и оно не загружено на страницу, при подключении бандла произойдёт фатальная ошибка — JavaScript не сможет обратиться к несуществующему неймспейсу (например, BX.Main.Core).

Параметр safeNamespaces включает optional chaining для обращений к неймспейсам зависимостей в IIFE-обёртке бандла. Если зависимость отсутствует, вместо фатальной ошибки расширение получит пустой объект. Это даёт возможность проверить наличие зависимости в коде и работать с ней условно:

js
if (BX.Main?.Core)
{
  // Зависимость загружена, можно использовать
}
ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My.Extension',
  safeNamespaces: true,
};

При включении зависимости в IIFE-обёртке будут обращаться через ?. и ??:

js
// Было:
})(this.BX.My.Extension = this.BX.My.Extension || {}, BX.Main.Core, BX.UI.Buttons);

// Стало:
})(this.BX.My.Extension = this.BX.My.Extension || {}, BX?.Main?.Core??{}, BX?.UI?.Buttons??{});

Собственный неймспейс расширения не трансформируется — он уже безопасно инициализируется в начале бандла.

Баннер ​

Параметр banner добавляет комментарий в JS-бандл при каждой сборке — например, копирайт, лицензию или другой юридический текст.

Строка добавляется в начало бандла:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  banner: 'Copyright (c) Bitrix24',
};

Чтобы выбрать место, передайте объект с полями top (начало) и bottom (конец). Можно указать одно из них или оба:

ts
export default {
  input: './src/index.ts',
  output: './dist/my.bundle.js',
  namespace: 'BX.My',
  banner: {
    top: 'Copyright (c) Bitrix24\nAll rights reserved',
    bottom: '// end of my.bundle',
  },
};

Результат:

js
/* eslint-disable */
/*!
 * Copyright (c) Bitrix24
 * All rights reserved
 */
this.BX = this.BX || {};
(function (exports) {
  // ...
})(this.BX.My = this.BX.My || {});
// end of my.bundle
//# sourceMappingURL=my.bundle.js.map

Как это работает:

  • Обычный текст оборачивается в юридический комментарий /*! ... */ — такие комментарии сохраняют минификаторы и сборщики, если бандл будет обработан повторно. Текст, который уже является комментарием (/*! ... */, /* ... */ или строки с //), вставляется как есть
  • Баннер в начале ставится сразу после строки /* eslint-disable */, а если её нет (в минифицированном бандле) — в самое начало. Баннер в конце — перед комментарием sourceMappingURL
  • Баннер добавляется в уже готовый бандл: его не удаляют ни очистка комментариев в TypeScript-сборке, ни минификация. При concat он оборачивает весь склеенный файл. Плагины из plugins видят бандл уже с баннером в хуках generateBundle и writeBundle
  • Source map сдвигается на добавленные строки, поэтому позиции в отладчике остаются верными
  • Баннер добавляется только в JS-бандл, CSS-бандл не меняется

Переменные окружения ​

Chef автоматически заменяет переменные окружения при сборке:

ПеременнаяProductionDevelopment
process.env.NODE_ENV"production""development"
import.meta.env.MODE"production""development"
import.meta.env.PRODtruefalse
import.meta.env.DEVfalsetrue

Замена происходит статически на этапе сборки. Это позволяет tree-shaking вырезать dev-only код из npm-пакетов:

ts
if (process.env.NODE_ENV !== 'production') {
  console.warn('Debug info');
}

В режиме chef build (без флагов) переменные подставляются как development. В режиме chef build --production — как production.

Распространяется под лицензией MIT.