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

Расширения FEOD для продвинутых проектов

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

SSR (Server-Side Rendering)

FEOD изначально спроектирован так, чтобы поддерживать SSR. Для работы с ним есть готовый пример, и, что важно, ключевые отличия кроются в организации приложения.

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

В реальности это выражается всего в двух файлах:

  • entry.server.ts — точка входа сервера
  • entry.client.ts — точка входа клиента

И на этом всё. Такая структура упрощает разделение обязанностей и делает приложение более прозрачным.

Если же мы говорим об использовании готовых фреймворков, то вы можете использовать их встроенные возможности для SSR и не подстраиваться схожим образом.

Пример структуры для SSR

  • src
    • app
      • server
        • entry.server.ts
      • entry.client.ts
      • router
      • layouts
      • config
    • pages
    • modules
    • common
    • globals

Dependency Injection

В FEOD акцент сделан на минимизацию кросс-модульных взаимодействий в пользу Inversion of Control. Одной из наиболее эффективных реализаций является Dependency Injection. Для этого можно использовать различные инструменты, например SDI (Simple Dependency Injection) или другие полноценные DI-решения.

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

Пример использования IoC

ts
// modules/Notifications/index.ts
export interface NotificationService {
  showSuccess(message: string): void
  showError(message: string): void
}

let notificationService: NotificationService

export function setNotificationService(service: NotificationService) {
  notificationService = service
}

export function getNotificationService(): NotificationService {
  if (!notificationService) {
    throw new Error('Notification service not initialized')
  }
  return notificationService
}

// app/integrations/notifications.ts
import { setNotificationService } from '@/modules/Notifications'
import { ToastService } from '@/modules/ToastUI'

setNotificationService(new ToastService())

// Использование в любом модуле:
import { getNotificationService } from '@/modules/Notifications'

const notifications = getNotificationService()
notifications.showSuccess('Operation completed successfully')

Преимущества IoC в FEOD

  • Явные зависимости — легко понять, от чего зависит модуль
  • Упрощённое тестирование — можно легко подменить реализации
  • Слабая связанность — модули не зависят от конкретных реализаций
  • Гибкость — можно менять реализации без изменения модулей

Интеграция с DDD (Domain-Driven Design)

Если в вашей команде много бэкенд-разработчиков и они привыкли мыслить в терминах DDD, FEOD легко подстраивается под этот подход. В модулях можно выделить дополнительные сущности — Entities и Adapters.

Для тех, кто знаком с DDD, назначение этих частей очевидно. Они помогают ещё чётче определять входы и выходы модуля, обеспечивая строгую структуру и понятные границы.

Пример структуры модуля с DDD

  • modules
    • UserManagement
      • domain
        • entities
          • User.ts
          • UserProfile.ts
        • value-objects
          • Email.ts
          • UserId.ts
      • adapters
        • primary
          • components
            • UserList.vue
            • UserForm.vue
        • secondary
          • api
            • userApi.ts
          • repositories
            • userRepository.ts
      • application
        • createUser.ts
        • updateUser.ts
        • getUserById.ts
      • index.ts

Entities в контексте FEOD

Entities в DDD-подходе представляют бизнес-сущности с их поведением. В FEOD они размещаются внутри модуля в папке domain/entities/.

ts
// modules/UserManagement/domain/entities/User.ts
export class User {
  constructor(
    private id: UserId,
    private email: Email,
    private profile: UserProfile
  ) {}
  
  updateEmail(newEmail: Email): void {
    this.email = newEmail
  }
  
  getId(): UserId {
    return this.id
  }
}

Adapters в контексте FEOD

Adapters обеспечивают взаимодействие модуля с внешним миром:

  • Primary adapters (входные) — UI-компоненты, которые используют модуль
  • Secondary adapters (выходные) — API-клиенты, репозитории, внешние сервисы
ts
// modules/UserManagement/adapters/secondary/api/userApi.ts
import { User } from '../../domain/entities/User'

export class UserApi {
  async fetchUser(id: string): Promise<User> {
    // Реализация API-запроса
  }
}

Такой способ интеграции FEOD особенно полезен для проектов, где требуется дисциплинированная архитектура и чёткое разделение между бизнес-логикой и техническими деталями.

Использование FEOD за пределами фронтенд-приложений

Открытый вопрос: можно ли использовать FEOD за пределами фронтенд-приложений? Например, в разработке инструментов для линтинга, UI-библиотек или любых других пакетов, которые сами по себе не являются фронтенд-приложениями.

Эта идея пока остаётся в стадии обсуждения и проработки. Но направление интересное: если удастся масштабировать FEOD на такие кейсы, мы получим универсальный архитектурный инструмент, применимый гораздо шире, чем просто в рамках интерфейсных проектов.

Потенциальные области применения

  • UI-библиотеки — организация компонентов и утилит
  • Инструменты разработки — линтеры, плагины, утилиты
  • BFF и полноценный бэкенд