Структура проекта и организация кода

Inferno — высокопроизводительный JavaScript-фреймворк для создания пользовательских интерфейсов. Организация кода и структура проекта играют ключевую роль в поддерживаемости приложений, особенно при работе с крупными проектами.


Основная структура проекта

Типичный проект на Inferno строится вокруг следующих директорий:

my-inferno-app/
├── public/
│   ├── index.html
│   └── assets/
├── src/
│   ├── components/
│   ├── pages/
│   ├── services/
│   ├── store/
│   ├── utils/
│   └── index.js
├── package.json
└── webpack.config.js

public/ — статические ресурсы, которые не обрабатываются сборщиком, включая корневой HTML-файл и изображения.

src/ — исходный код приложения, делится на логические блоки.


Компоненты

В components/ размещаются переиспользуемые UI-элементы. Для Inferno рекомендуется использовать функциональные компоненты с хуками, так как они проще и эффективнее в работе с виртуальным DOM.

Пример структуры:

components/
├── Button/
│   ├── Button.jsx
│   └── Button.css
├── Header/
│   ├── Header.jsx
│   └── Header.css
└── Footer/
    ├── Footer.jsx
    └── Footer.css

Особенности организации компонентов:

  • Каждый компонент хранится в отдельной папке с сопутствующими стилями и тестами.
  • Используется именование PascalCase для компонентов (Header, UserCard).
  • Стили можно инкапсулировать через CSS-модули или styled-components.

Страницы и маршрутизация

Каталог pages/ содержит компоненты, представляющие отдельные страницы приложения. Например:

pages/
├── HomePage.jsx
├── AboutPage.jsx
└── ProfilePage.jsx

Для навигации между страницами применяется inferno-router:

import { Router, Route, Link } from 'inferno-router';
import HomePage from './pages/HomePage';
import AboutPage from './pages/AboutPage';

const App = () => (
  <Router>
    <Route path="/" component={HomePage} />
    <Route path="/about" component={AboutPage} />
  </Router>
);

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

  • Страницы должны быть относительно “тонкими” и содержать минимальную логику.
  • Вся бизнес-логика выносится в сервисы или контейнерные компоненты.

Сервисы и бизнес-логика

Каталог services/ предназначен для работы с API, бизнес-логики, утилит для работы с данными. Пример:

services/
├── api.js
├── authService.js
└── userService.js

api.js

export const fetchUser = async (id) => {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
};

Принципы организации:

  • Сервисы должны быть независимыми и не содержать UI-кода.
  • Использовать единый интерфейс для всех внешних запросов.
  • Возможность переиспользования в разных компонентах.

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

Для глобального состояния приложения можно использовать Inferno-Redux или MobX. Структура каталога store/ может быть следующей:

store/
├── actions/
├── reducers/
├── selectors/
└── store.js

Пример редьюсера:

const initialState = { user: null };

export const userReducer = (state = initialState, action) => {
  switch(action.type) {
    case 'SET_USER':
      return { ...state, user: action.payload };
    default:
      return state;
  }
};

Основные принципы:

  • Разделение действий, редьюсеров и селекторов по логическим блокам.
  • Минимизация побочных эффектов в редьюсерах.
  • Использование хуков useStore для доступа к состоянию внутри компонентов.

Утилиты и хелперы

Каталог utils/ хранит вспомогательные функции, которые не зависят от UI:

utils/
├── formatDate.js
├── debounce.js
└── validate.js

Пример:

export const debounce = (func, delay) => {
  let timeout;
  return (...args) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => func(...args), delay);
  };
};

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

  • Утилиты должны быть атомарными и решать одну задачу.
  • Использовать единый стиль именования и экспорта.

Точка входа

src/index.js подключает корневой компонент и рендерит его в DOM:

import { render } from 'inferno';
import App from './App';

render(<App />, document.getElementById('root'));

Советы:

  • Минимизировать логику в точке входа.
  • Инициализация глобальных сервисов, роутера и состояния выполняется здесь.

Стилизация

Возможные подходы:

  • CSS/SCSS файлы на компонент.
  • CSS-модули для инкапсуляции стилей.
  • Styled-components или Emotion для динамической стилизации.

Пример CSS-модуля:

/* Button.module.css */
.button {
  background-color: blue;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
}
import styles from './Button.module.css';

const Button = ({ children }) => <button className={styles.button}>{children}</button>;

Тестирование

Рекомендуется использовать Jest и Inferno Testing Library для модульных и интеграционных тестов. Структура может быть следующей:

components/
├── Button/
│   ├── Button.jsx
│   └── Button.test.js

Пример теста:

import { render } from '@testing-library/inferno';
import Button from './Button';

test('отображает текст кнопки', () => {
  const { getByText } = render(<Button>Click me</Button>);
  expect(getByText('Click me')).toBeDefined();
});

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

  • Тестировать компоненты изолированно.
  • Проверять ключевые функции сервисов и утилит.

Структура проекта в Inferno должна быть логичной, модульной и предсказуемой. Ясное разделение компонентов, страниц, сервисов, состояния и утилит позволяет масштабировать приложения и облегчает сопровождение кода.