BetaДокументация для beta‑теста, возможны ошибки и неточности.
Перейти к содержимому

WARNING

Эта статья сгенерирована AI и требует ручной доработки.

Паттерны FEOD ​

В этой статье собраны практические паттерны, которые опираются на правила FEOD и помогают держать модули изолированными, а структуру — предсказуемой.

1. Публичный API модуля ​

Идея: любой доступ к модулю идёт через index.ts. Это защищает внутренности и упрощает рефакторинг.

modules/
  Billing/
    index.ts
    api/
    composables/
    types/
ts
// modules/Billing/index.ts
export { createInvoice } from './api/createInvoice'
export { useBilling } from './composables/useBilling'
export type { Invoice } from './types'

2. Фрактальный разрез ​

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

modules/
  Billing/
    modules/
      Invoices/
      Payments/

Подмодуль сам изолирован и экспортирует свой API через index.ts.

3. Композиция на уровне Pages ​

Идея: страницы не содержат бизнес-логики, они собирают модули в сценарий.

text
pages/
  dashboard.vue
vue
<!-- pages/dashboard.vue -->
<script setup lang="ts">
import { UserSummary } from '@/modules/UserSummary'
import { BillingOverview } from '@/modules/Billing'
</script>

<template>
  <main>
    <UserSummary />
    <BillingOverview />
  </main>
</template>

Каждый модуль экспортирует свой компонент через index.ts. Страница определяет их расположение, а загрузка данных остаётся внутри модулей.

4. Интеграции живут в App ​

Идея: внешние сервисы подключаются в app, а модули остаются независимыми.

text
app/
  entry.ts
  integrations/
    analytics.ts
modules/
  Analytics/
    index.ts
ts
// modules/Analytics/index.ts
export interface AnalyticsClient {
  track(event: string): void
}

export function createAnalytics(client: AnalyticsClient) {
  return { pageOpened: () => client.track('page_opened') }
}
ts
// app/integrations/analytics.ts
import { createAnalytics } from '@/modules/Analytics'

export const analytics = createAnalytics({
  track(event) {
    void fetch('/api/events', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ event }),
      keepalive: true
    }).catch(() => { /* Телеметрия не блокирует страницу. */ })
  }
})
analytics.pageOpened()

В app/entry.ts импортируется analytics из ./integrations/analytics; импорт выполняет показанную настройку и отправку события.

5. Вынос в Common только при универсальности ​

Идея: в common попадают только универсальные, одиночные сущности. Если требуется несколько файлов или появляется бизнес-смысл, это уже modules.

common/
  utilities/
    formatDate.ts
modules/
  Orders/
    utilities/
      calculateTotals.ts

6. Приватный модуль страницы ​

Идея: если странице нужна локальная логика, используйте приватный модуль с префиксом _.

pages/
  orders/
    index.vue
    _orders/
      index.ts
      components/
        OrderList.vue
ts
// pages/orders/_orders/index.ts
export { default as OrderList } from './components/OrderList.vue'
vue
<!-- pages/orders/index.vue -->
<script setup lang="ts">
import { OrderList } from './_orders'
</script>

<template><OrderList /></template>

Приватный модуль не используется вне своей страницы.

7. Зигзагообразные импорты запрещены ​

Идея: подмодуль не должен импортировать внешний уровень своего модуля или соседний подмодуль другого модуля.

modules/
  A/
    modules/
      A1/
  B/
    modules/
      B1/

A1 не импортирует B1 напрямую — только публичный API B.

ts
// modules/A/modules/A1/load.ts
import { loadBilling } from '@/modules/B' // допустимо: публичный API B
ts
// modules/A/modules/A1/load.ts
import { loadPayments } from '@/modules/B/modules/B1' // запрещено: обход API B