Skip to content

Компонент, директива и composables

Опции инициализации

ts
app.use(FeatureToggles, {
  // Статические значения флагов (boolean или строка варианта)
  flags: { newDashboard: true, checkoutFlow: 'v2' },

  // Асинхронный загрузчик — получает флаги с бэкенда
  loader: async () => {
    const res = await fetch('/api/feature-flags')
    return res.json()
  },

  // Интервал поллинга для загрузчика в мс (по умолчанию: 0 = отключено)
  reloadInterval: 60_000,

  // Разрешить ?feature:flagName=true в URL (по умолчанию: true в dev, false в prod)
  urlOverrides: true,

  // Префикс URL-параметра (по умолчанию: 'feature')
  urlPrefix: 'feature',

  // Значение, возвращаемое для неизвестных флагов (по умолчанию: false)
  defaultValue: false,

  // Переменные, привязанные к флагу
  variables: {
    newCheckout: { maxItems: 5, theme: 'dark' },
  },

  // Именованные группы флагов
  groups: {
    beta: ['betaSearch', 'newDashboard'],
    maintenance: ['maintenanceMode', 'readOnlyBanner'],
  },

  // Обеспечение зависимостей: если требуемый флаг выключен, зависимый тоже принудительно выключается
  dependencies: {
    aiSuggestions: ['newSearch'],
  },

  // Контекстные правила — вычисляются реактивно, приоритет ниже setFlag/URL
  rules: {
    darkMode: () => window.matchMedia('(prefers-color-scheme: dark)').matches,
  },

  // Метаданные флагов для DevTools и CLI
  meta: {
    newDashboard: {
      description: 'New UI',
      owner: 'alice',
      addedAt: '2025-03-01',
      ticket: 'PROJ-42',
    },
  },

  // Даты автоматического истечения — после этой даты флаг считается истёкшим
  expiry: {
    christmasBanner: '2025-01-10',
  },

  // Живые обновления с сервера (SSE или WebSocket)
  liveUpdates: {
    type: 'sse',
    url: '/api/flags/stream',
  },

  // Серверный снимок флагов для предотвращения расхождения при гидратации
  ssrState: window.__FEATURE_FLAGS__,
})

Компонент <Feature>

vue
<!-- Базовый -->
<Feature name="newDashboard">
  <NewDashboard />
</Feature>

<!-- Слот fallback -->
<Feature name="betaSearch">
  <template #default><BetaSearchBar /></template>
  <template #fallback><LegacySearchBar /></template>
</Feature>

<!-- Проп fallback -->
<Feature name="betaSearch" fallback="Feature is under development">
  <BetaSearchBar />
</Feature>

<!-- Инвертированный — показывать, когда флаг выключен -->
<Feature name="maintenanceMode" :inverted="true">
  <MainContent />
</Feature>

<!-- Обернуть в HTML-элемент -->
<Feature name="newDashboard" tag="section">
  <NewDashboard />
</Feature>

<!-- Состояние загрузки, пока работает загрузчик -->
<Feature name="loaderFlag">
  <template #loading><Spinner /></template>
  <template #default><NewFeature /></template>
  <template #fallback><OldFeature /></template>
</Feature>

<!-- Группа — показывать, когда ВСЕ флаги в группе включены -->
<Feature group="beta">
  <BetaLabel />
</Feature>

Пропы

ПропТипПо умолчаниюОписание
namestringИмя флага
groupstringИмя группы (альтернатива name)
fallbackstring | ComponentnullЧто рендерить, когда флаг выключен
invertedbooleanfalseРендерить, когда флаг равен false
tagstringОбернуть содержимое в HTML-элемент (по умолчанию без обёртки)

Слоты

СлотОписание
defaultСодержимое, когда флаг включён
fallbackСодержимое, когда флаг выключен
loadingСодержимое, пока флаги загружаются через loader

Директива v-feature

vue
<!-- Показывать, когда флаг включён -->
<div v-feature="'newDashboard'">...</div>

<!-- Показывать, когда флаг выключен (инвертировано) -->
<div v-feature:not="'betaSearch'">...</div>

<!-- Показывать, когда ВСЕ флаги включены -->
<div v-feature="['newDashboard', 'betaSearch']">...</div>

Работает как v-show (переключает display: none) — узел DOM всегда присутствует. Для поведения в стиле v-if используйте <Feature>.

useFeature

ts
import { useFeature } from 'vue-feature-toggles'

// Один флаг → Ref<boolean>
const isNewDashboard = useFeature('newDashboard')

// Несколько флагов → Record<string, Ref<boolean>>
const { newDashboard, betaSearch } = useFeature(['newDashboard', 'betaSearch'])

// Проверка AND по нескольким флагам → Ref<boolean>
const allEnabled = useFeature('newDashboard', 'betaSearch')

Мультивариантные флаги и <FeatureVariant>

Флаги могут содержать строковый вариант вместо boolean — полезно для A/B-тестов и многоэтапных раскаток.

ts
app.use(FeatureToggles, {
  flags: { checkoutFlow: 'v2' },
})
ts
import { useFeatureVariant } from 'vue-feature-toggles'

const variant = useFeatureVariant('checkoutFlow') // Ref<string>
vue
<FeatureVariant name="checkoutFlow">
  <template #v1><CheckoutV1 /></template>
  <template #v2><CheckoutV2 /></template>
  <template #fallback><CheckoutLegacy /></template>
</FeatureVariant>

URL-переопределения работают идентично: ?feature:checkoutFlow=v2.