← Назад к вопросам

Используешь ли модули

2.2 Middle🔥 191 комментариев
#Soft Skills и рабочие процессы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Использование модулей в Frontend

Да, модули — это основа современной JavaScript разработки. Я использую их постоянно и считаю правильную организацию модулей критичной для качества кода.

Что такое модули?

Модуль — это самодостаточный файл с кодом, который экспортирует функциональность и может импортировать то, что ему нужно. Это позволяет разбить большое приложение на маленькие, управляемые куски.

ESM (ES Modules) — современный стандарт

// utils/math.js
export function add(a, b) {
  return a + b;
}

export const PI = 3.14159;

// components/Button.jsx
import { add, PI } from '../utils/math.js';

export function Button() {
  const result = add(2, 3);
  return <button>Result: {result}</button>;
}

Типы экспортов

Named export

// utils.js
export function greet(name) {
  return `Hello, ${name}`;
}

export const APP_NAME = 'MyApp';

// app.js
import { greet, APP_NAME } from './utils.js';
console.log(greet('Alice')); // Hello, Alice

Default export

// Button.jsx
export default function Button() {
  return <button>Click me</button>;
}

// app.jsx
import Button from './Button.jsx';
// Можешь назвать как угодно

Комбинированно

// Button.jsx
export default function Button() {
  return <button>Click</button>;
}

export const BUTTON_STYLES = { /* ... */ };

// app.jsx
import Button, { BUTTON_STYLES } from './Button.jsx';

Структура модулей в приложении

В большом приложении модули организуют по слоям:

src/
  domain/          # Бизнес логика (независима от framework)
    user/
      types.ts     # User, UserProfile интерфейсы
      validators.ts
  
  application/     # Use cases, бизнес правила
    user/
      getUserById.ts
      updateUser.ts
  
  infrastructure/  # API клиент, БД, внешние сервисы
    api/
      client.ts
      endpoints.ts
  
  presentation/    # UI компоненты
    components/
      Button.jsx
      UserCard.jsx
    pages/
      HomePage.jsx
    hooks/
      useUser.ts

Практические примеры

1. Разделение логики и UI

// hooks/useUser.ts
export function useUser(userId) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchUser(userId)
      .then(setUser)
      .catch(setError)
      .finally(() => setLoading(false));
  }, [userId]);

  return { user, loading, error };
}

// components/UserProfile.jsx
import { useUser } from '../hooks/useUser';

export function UserProfile({ userId }) {
  const { user, loading, error } = useUser(userId);
  
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  return <div>{user.name}</div>;
}

2. Утилиты и константы

// utils/formatters.ts
export function formatDate(date) {
  return date.toLocaleDateString('en-US');
}

export function formatCurrency(amount) {
  return `$${amount.toFixed(2)}`;
}

// constants.ts
export const API_BASE_URL = process.env.REACT_APP_API_URL;
export const PAGINATION_SIZE = 20;
export const CACHE_TTL = 5 * 60 * 1000; // 5 минут

// components/PriceTag.jsx
import { formatCurrency } from '../utils/formatters';
import { CACHE_TTL } from '../constants';

export function PriceTag({ price }) {
  return <span>{formatCurrency(price)}</span>;
}

3. Custom хуки как модули

// hooks/useLocalStorage.ts
export function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    const item = window.localStorage.getItem(key);
    return item ? JSON.parse(item) : initialValue;
  });

  const setValue = (value) => {
    setStoredValue(value);
    window.localStorage.setItem(key, JSON.stringify(value));
  };

  return [storedValue, setValue];
}

// components/ThemeSelector.jsx
import { useLocalStorage } from '../hooks/useLocalStorage';

export function ThemeSelector() {
  const [theme, setTheme] = useLocalStorage('theme', 'light');
  
  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      Current theme: {theme}
    </button>
  );
}

4. API клиент как модуль

// lib/api.ts
class ApiClient {
  constructor(baseURL, token) {
    this.baseURL = baseURL;
    this.token = token;
  }

  async request(endpoint, options = {}) {
    const url = `${this.baseURL}${endpoint}`;
    const headers = {
      'Content-Type': 'application/json',
      ...(this.token && { 'Authorization': `Bearer ${this.token}` }),
      ...options.headers
    };

    const response = await fetch(url, { ...options, headers });
    
    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }

    return response.json();
  }

  get(endpoint) {
    return this.request(endpoint);
  }

  post(endpoint, data) {
    return this.request(endpoint, {
      method: 'POST',
      body: JSON.stringify(data)
    });
  }
}

export const api = new ApiClient(
  process.env.REACT_APP_API_URL,
  localStorage.getItem('token')
);

// components/UserList.jsx
import { api } from '../lib/api';

export function UserList() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    api.get('/users').then(setUsers);
  }, []);

  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

Лучшие практики с модулями

1. Одна ответственность на модуль

// ПЛОХО: всё в одном файле
// Button.jsx содержит Button, IconButton, LoadingButton...

// ХОРОШО: разные модули
// Button.jsx — только Button
// IconButton.jsx — только IconButton
// LoadingButton.jsx — только LoadingButton

2. Явные экспорты

// ПЛОХО: экспортируем всё подряд
export * from './utils';

// ХОРОШО: явно выбираем что экспортировать
export { formatDate, formatCurrency } from './utils';

3. Правильная структура импортов

// ПОРЯДОК ИМПОРТОВ:
// 1. Внешние библиотеки
import React from 'react';
import { useEffect, useState } from 'react';

// 2. Внутренние модули (абсолютные пути)
import { api } from '@/lib/api';
import { useUser } from '@/hooks/useUser';

// 3. Локальные модули (относительные пути)
import { UserCard } from './UserCard';
import styles from './UserList.module.css';

// ПУСТО

// Код компонента
export function UserList() { /* ... */ }

4. Избегай циклических зависимостей

// ПЛОХО: A импортирует B, B импортирует A
// userService.js
import { logger } from './logger';

// logger.js
import { userService } from './userService'; // Циклическая зависимость!

// ХОРОШО: используй разные модули
// domain/user.ts (типы)
// application/userService.ts
// infrastructure/logger.ts

5. Барьелы (index.ts)

// components/index.ts
export { Button } from './Button';
export { Card } from './Card';
export { Modal } from './Modal';

// app.jsx
// ВМЕСТО:
import { Button } from './components/Button';
import { Card } from './components/Card';
import { Modal } from './components/Modal';

// ПИШЕШЬ:
import { Button, Card, Modal } from './components';

Модули и производительность

Tree-shaking

Сборщик удаляет неиспользуемые экспорты:

// utils.js
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }

// app.js
import { add } from './utils'; // Используем только add

// Сборщик удалит subtract из финального бандла

Code splitting

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

import { lazy, Suspense } from 'react';

const AdminPanel = lazy(() => import('./pages/AdminPanel'));

export function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <AdminPanel />
    </Suspense>
  );
}

Итог

Модули — это стандарт современного JavaScript. Они позволяют:

  • Организовать код в понятную структуру
  • Избежать конфликтов имён (каждый модуль имеет своё пространство)
  • Переиспользовать код (импортируй модуль везде)
  • Тестировать каждый модуль отдельно
  • Оптимизировать приложение (tree-shaking, code splitting)

Правильное использование модулей — это основа чистого, поддерживаемого кода.