Skip to content

Конфигурация

utilsJIT принимает объект настроек.

ts
import { defineConfig } from 'vite'
import { utilsJIT } from '@vueland/utils-jit'

export default defineConfig({
  plugins: [
    utilsJIT({
      include: [/\.(vue|js|ts|jsx|tsx|html|svelte|astro)$/],
      exclude: [/src\/fixtures/],
      emitFile: false,
      outFile: 'src/.generated/utils-jit.css',
      breakpoints: {
        xs: 0,
        sm: 600,
        md: 960,
        lg: 1280,
        xl: 1920,
        xxl: 2560,
      },
      debug: false,
    }),
  ],
})

Плагин фреймворка (@vitejs/plugin-vue, @vitejs/plugin-react и т.д.) добавляйте в тот же массив plugins, если он нужен приложению.

Options

Option
Тип
По умолчанию
Описание
include
Array<string | RegExp>
[/\.(vue|js|ts|jsx|tsx|html|svelte|astro)$/]
Файлы, которые нужно анализировать.
exclude
Array<string | RegExp>
Служебные директории
Файлы и директории, которые нужно исключить.
emitFile
boolean
false
Дополнительно писать CSS в файл (для дебага). По умолчанию CSS отдаётся только виртуальным модулем.
outFile
string
src/.generated/utils-jit.css
Путь к дебаг-файлу относительно Vite root. Используется только при emitFile: true.
breakpoints
Record<string, number>
{ xs: 0, sm: 600, md: 960, lg: 1280, xl: 1920, xxl: 2560 }
Брейкпоинты для адаптивных вариантов. При передаче мёржатся с дефолтными (переопределяют значения по ключу, новые ключи добавляются как CSS-префиксы).
attrs
AttrRule[]
[]
Пользовательские атрибуты/пропы, литеральные значения которых генерируют arbitrary utility candidates. См. Custom attrs.
rules
UtilityRule[]
[]
Пользовательские utility-правила.
variants
VariantMap
{}
Пользовательские variants, которые добавляются к встроенным variants.
banner
string
/* @vueland/utils-jit: generated utilities */
Баннер в начале итогового CSS.
emitEmptyFile
boolean
true
Отдавать плейсхолдер-комментарий, если utilities не найдены (иначе пустой CSS).
debug
boolean
false
Выводить диагностические сообщения.

emitFile

По умолчанию CSS отдаётся виртуальным модулем virtual:utils-jit.css и на диск не пишется — потребитель импортирует модуль:

ts
import 'virtual:utils-jit.css'

Если нужно увидеть результат файлом (для дебага, инспекции диффов, внешних инструментов), включите emitFile — CSS дополнительно запишется в outFile. Доставку это не меняет: импортировать всё равно нужно виртуальный модуль.

ts
utilsJIT({
  emitFile: true,
})

outFile

Путь до дебаг-файла относительно root Vite-проекта. Используется только при emitFile: true — в обычном режиме файл не пишется.

ts
utilsJIT({
  emitFile: true,
  outFile: 'src/styles/generated/utils.css',
})

Импортировать по-прежнему нужно виртуальный модуль, а не этот файл:

ts
import 'virtual:utils-jit.css'

include

Список паттернов для файлов, которые нужно анализировать.

По умолчанию:

ts
;[/\.(vue|js|ts|jsx|tsx|html|svelte|astro)$/]

Пример:

ts
utilsJIT({
  include: [/\.(vue|ts)$/],
})

Vue, React, Preact, Solid, Svelte, Astro, HTML, JS и TS файлы включены по умолчанию. Для других типов файлов добавьте их расширения явно:

ts
utilsJIT({
  include: [/\.(vue|js|ts|jsx|tsx|html|svelte|astro|mdx)$/],
})

exclude

Список паттернов для файлов и директорий, которые нужно исключить из полного сканирования, transform и HMR.

По умолчанию исключаются:

txt
node_modules
.git
dist
build
coverage
.output
.nuxt
.turbo
.generated
storybook-static
playwright-report

Пример:

ts
utilsJIT({
  exclude: [/src\/fixtures/, /src\/legacy/, 'storybook-static'],
})

breakpoints

Объект брейкпоинтов для адаптивных вариантов. Ключ используется как префикс класса, значение — min-width в пикселях. При передаче мёржится со встроенными дефолтами (xs: 0, sm: 600, md: 960, lg: 1280, xl: 1920, xxl: 2560): переданные ключи переопределяют значения, остальные дефолтные имена сохраняются.

ts
utilsJIT({
  breakpoints: {
    xs: 0,
    sm: 600,
    md: 960,
    tablet: 1280,
    lg: 1280,
    xl: 1920,
    xxl: 2560,
  },
})

Почему мерж, а не замена

В самостоятельном использовании merge позволяет переопределить одно значение и не потерять встроенные адаптивные префиксы. В Vueland-приложении эти же имена (xs/sm/md/lg/xl/xxl) ещё и общий контракт: @vueland/ui генерит из них предопределённые .md\:pa-4, .lg\:d-flex и встроенные адаптивные пропсы CRow/CCol, а useBreakpoints отдаёт их в рантайм. Поэтому можно переопределять значения и добавлять новые имена (например tablet: 1280), но дефолтные имена остаются доступными.

После этого новый префикс можно использовать в JIT-классах:

html
<div class="sm:w-[640px] tablet:w-[1024px] lg:w-[1280px]"></div>

Vueland UI: кастомные имена брейкпоинтов в grid-компонентах

Кастомные имена компилируются в CSS сетки, но Vue-компоненты не получают новые пропы для этих ключей. Например, breakpoints: { tablet: 1280 } сгенерирует tablet-классы сетки, но не сделает <c-col tablet="6"> или <c-row align-tablet="center"> валидными пропами.

Для кастомных имён используйте обычные class/:class:

vue
<template>
  <c-row class="tablet:justify-center">
    <c-col cols="12" class="tablet-6">Половина ширины с tablet</c-col>
    <c-col cols="12" class="tablet-4 tablet:offset-1">Треть ширины с tablet</c-col>
  </c-row>
</template>

Дефолтные breakpoint-пропы вроде sm="6", md="4", align-md="center" и justify-lg="space-between" остаются доступными и используют значения, настроенные через utilsJIT.

Ограничения на имена ключей

Ключи могут быть любыми строками — они становятся CSS-префиксами и валидны в этом контексте. Однако если вы используете @vueland/ui и хотите, чтобы те же брейкпоинты применялись к предопределённым SCSS-утилитам (sm:d-flex, md:pa-4), ключи должны быть валидными SCSS-идентификаторами: не могут начинаться с цифры.

Ключ
JIT-классы
SCSS-утилиты (с @vueland/ui)
sm, md, xxl
'2xl', '3xl'
✗ невалидный SCSS-идентификатор

Если @vueland/ui SCSS не используется, ключи вида '2xl' работают без ограничений.

attrs

Используйте attrs, чтобы сканировать пользовательские компонентные пропы или атрибуты, литеральные значения которых создают utility-классы в runtime. Каждая запись настраивается через defineAttr; примеры, валидаторы и поведение color-пропа @vueland/ui описаны на странице Custom attrs.

variants

Пользовательские variants позволяют расширять синтаксис состояний.

ts
utilsJIT({
  variants: {
    hocus: {
      kind: 'selector',
      value: '&:hover,&:focus',
    },
    selected: {
      kind: 'attribute',
      value: '[aria-selected="true"]',
    },
    tablet: {
      kind: 'media',
      value: 900,
    },
    dark: {
      kind: 'selector',
      value: '[data-theme="dark"] &',
    },
  },
})

emitEmptyFile

Если emitEmptyFile: true (по умолчанию) и utility-классы не найдены, виртуальный модуль отдаёт плейсхолдер-комментарий (и тот же текст пишется в дебаг-файл при emitFile):

css
/* @vueland/utils-jit: no utilities found */

Если emitEmptyFile: false, при отсутствии utility-классов отдаётся пустой CSS.

ts
utilsJIT({
  emitEmptyFile: false,
})

Работа со строками классов

Плагин сканирует статические class-like строки в файлах, которые подходят под include. Он понимает обычный HTML/Vue class, Vue :class, React/Preact className, а также строковые литералы в массивах и объектах.

Vue-примеры:

vue
<template>
  <div class="w-[200px]"></div>
  <div :class="['w-[200px]', active && 'px-[16px]']"></div>
  <div :class="{ 'radius-[12px]': rounded }"></div>
</template>

React-пример:

tsx
export function Card({ active }: { active: boolean }) {
  return <div className={active ? 'w-[320px] px-[16px]' : 'w-[240px] px-[12px]'}>Content</div>
}

Кроме классов, плагин может сканировать пользовательские литеральные атрибуты, настроенные через attrs. В проектах с @vueland/ui встроенный проп color сканируется автоматически.

Runtime-значения не вычисляются. Класс должен существовать в исходном коде как статический токен.

Не сработает:

vue
<script setup lang="ts">
const width = 320
</script>

<template>
  <div :class="`w-[${width}px]`"></div>
</template>

Сработает:

vue
<template>
  <div :class="isWide ? 'w-[320px]' : 'w-[240px]'"></div>
</template>

Как работает генерация

Во время запуска Vite плагин:

  1. Обходит файлы проекта.
  2. Пропускает служебные директории вроде node_modules, .git, dist, build, .generated и других.
  3. Анализирует только файлы, подходящие под include.
  4. Извлекает utility-токены.
  5. Валидирует значения.
  6. Отдаёт итоговый CSS виртуальным модулем virtual:utils-jit.css (и опц. дебаг-файлом при emitFile).

Во время разработки плагин обновляет CSS инкрементально:

  • добавляет правила для новых токенов;
  • удаляет правила, если токен больше нигде не используется;
  • не удаляет правило, если такой же токен используется в другом файле;
  • пропускает повторную токенизацию файлов с неизменившимся содержимым;
  • переиспользует cache разбора токенов и CSS-правил;
  • инвалидирует виртуальный модуль для горячей замены (HMR) без перезагрузки страницы.

Ограничения и безопасность

Чтобы не генерировать небезопасный или некорректный CSS, плагин ограничивает arbitrary-значения:

  • минимальная длина токена: 5;
  • максимальная длина токена: 180;
  • максимальная длина значения: 160;
  • запрещены ;, {, }, <, >;
  • запрещены CSS comments внутри значения;
  • значение должно содержать хотя бы одну букву или цифру;
  • разрешены только безопасные символы для CSS-значений.

Эта проверка применяется к полученному значению встроенных правил и пользовательских defineRule до вызова validate или declaration конкретного правила.

Поэтому такие классы будут проигнорированы:

html
<div class="w-[;]"></div>
<div class="w-[{}]"></div>
<div class="w-[<script>]"></div>
<div class="w-[...........................................]"></div>

Рекомендации

Используйте Utils JIT для точечных arbitrary-значений и проектных генерируемых утилит. Лучше всего он работает как сфокусированный слой рядом с дизайн-системой: повторяющиеся семантические решения держите в theme tokens, presets или вариантах компонентов, а JIT используйте для значений и правил, которые действительно нужно генерировать по исходникам.

Хорошо:

vue
<template>
  <c-card class="max-w-[720px] px-[24px] radius-[16px]"> Content </c-card>
</template>

Также хорошо подходят локальные пользовательские утилиты:

ts
defineRule({
  name: 'grid-cols',
  matcher: /^grid-cols-(\d+)$/,
  declaration: (value) => ({
    display: 'grid',
    gridTemplateColumns: `repeat(${value}, minmax(0, 1fr))`,
  }),
})

Если значение или поведение становится глобальным решением дизайн-системы, лучше перенести его в theme token, preset или вариант компонента.

Устранение проблем

Утилиты не применяются

Проверьте, что:

  • utilsJIT() добавлен в vite.config.ts;
  • приложение импортирует virtual:utils-jit.css в точке входа;
  • в проекте есть хотя бы один поддерживаемый utility-класс;
  • файл с классами подходит под include;
  • файл не попадает под exclude.

Если utility-классы не найдены и emitEmptyFile: true, виртуальный модуль отдаёт комментарий:

css
/* @vueland/utils-jit: no utilities found */

Если emitEmptyFile: false, при отсутствии классов отдаётся пустой CSS.

Если включён emitFile: true, но дебаг-файл не появился — проверьте, что путь outFile корректен и пишется в пределах проекта.

Класс есть, но CSS не генерируется

Проверьте, что:

  • файл подходит под include;
  • файл не попадает под exclude;
  • класс написан статически, а не собирается в runtime;
  • значение проходит валидацию;
  • utility поддерживается встроенными правилами или добавлен через rules;
  • variant существует в breakpoints или variants.

Не работает адаптивный префикс

Префикс должен быть именем существующего брейкпоинта. Дефолтный набор — xs, sm, md, lg, xl, xxl; чтобы добавить свой (например tablet), передайте его в breakpoints — он смёржится с дефолтными:

ts
utilsJIT({
  breakpoints: {
    tablet: 900, // добавится к дефолтным xs/sm/md/lg/xl/xxl
  },
})

Если вы также используете SCSS-утилиты @vueland/ui, избегайте ключей начинающихся с цифры ('2xl', '3xl'). См. Ограничения на имена ключей.

Не работает custom rule

Проверьте, что matcher описывает именно utility-часть без variants.

Для класса:

html
<div class="hover:surface-[#fff]"></div>

matcher должен матчить:

txt
surface-[#fff]