<div><img src="https://top-fwz1.mail.ru/counter?id=3548135;js=na" style="position:absolute;left:-9999px;" alt="Top.Mail.Ru" /></div>
Публичное облако на базе VMware с управлением через vCloud Director
Вход / Регистрация

Создание интернет-магазина на Node.js с нуля. Часть 3: Фронтенд

14
40 минут чтения
Средний рейтинг статьи: 5

Продолжаем цикл статей про создание интернет-магазина. В прошлой статье вы узнали, как создать RestAPI на Node.js, сегодня мы перейдем к верстке сайта. 

Как упоминалось в первой части, будем использовать React.js — так что перед началом верстки вас ждет немного теории. Немного, обещаем.

Полный код из статьи можно найти на GitHub.

cloud

Что такое React.js

React.js — одна из самых популярных библиотек JavaScript для построения современных пользовательских интерфейсов. Плюсы React — удобство, производительность и большое сообщество разработчиков.

Основные концепции и возможности React.js

Компонентная архитектура

В React приложения строятся из независимых компонентов. Каждый компонент ответственен за определенную область экрана и может иметь собственное состояние (state) и свойства (props). Это позволяет разделить интерфейс на небольшие части, каждая из которых может повторно использоваться и тестироваться отдельно друг от друга.

Пример компонента:

import React from 'react';

const Button = ({ label }) => {
  return <button>{label}</button>;
};

export default Button;

Virtual DOM

DOM (Document Object Model, объектная модель документа) — это интерфейс программирования приложений (API), представляющий структуру HTML, XHTML- или XML-документа в виде дерева объектов. Это стандартизированное представление документов, которое позволяет программам манипулировать содержимым, структурой и стилем веб-страниц динамически посредством JavaScript или других языков сценариев.

Основные компоненты DOM включают:

  • Узлы (Nodes)

    • Документ представлен иерархической структурой узлов, каждый узел представляет собой элемент, атрибут, текстовое содержимое или комментарий. Типы узлов:

    • Элементы (Element): теговые элементы вроде <div>, <p> и др.

    • Атрибуты (Attr): значения атрибутов элементов, такие как id="header".

    • Текстовые узлы (Text): содержание между открывающим и закрывающим тегами элемента.

    • Комментарии (Comment): комментарии внутри HTML-кода.

  • Дерево DOM 

    • Каждый документ имеет корневой узел (document), от которого строятся дочерние узлы.

  • API DOM

    • Выбор узла: document.getElementById(), document.querySelector().

    • Создание/изменение: createElement(), appendChild(), setAttribute().

    • Удаление: removeChild(), innerHTML = ''.

    • Обработка событий: addEventListener() для реагирования на клики, нажатия клавиш и прочие события.

В свою очередь, React не работает непосредственно с DOM браузера. Вместо этого он создает собственную виртуальную версию дерева элементов страницы («virtual DOM»). Когда данные меняются, React вычисляет различия между старым и новым состоянием виртуального DOM и применяет минимально необходимые обновления к реальному DOM. Такой подход обеспечивает высокую производительность и уменьшает количество обращений к медленному API браузера.

Односторонний поток данных

React придерживается принципа однонаправленного потока данных. Этот принцип заключается в следующем: данные передаются строго сверху вниз, от родителя к потомкам, а обратная связь осуществляется через специальные обработчики событий (callbacks), идущие снизу вверх.

Почему это важно?

  • Простота понимания: Каждый компонент получает определенные свойства (props), зная точно, откуда пришли эти данные и куда идут изменения.

  • Предсказуемость изменений: Любое изменение состояния компонента вызывает предсказуемый процесс обновления интерфейса.

  • Отладка проще: Поскольку направление передачи данных фиксировано, легче выявить источник проблемы.

Как работает передача данных?

Рассмотрим детальнее два основных механизма, обеспечивающих однонаправленную передачу данных:

При помощи props

Родительские компоненты передают данные своим дочерним компонентам через механизм свойств (props). Например:

Родительский компонент App.js:

import { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: 'Иван',
      age: 30,
    };
  }

  render() {
    return (
      <div className="App">
        {/* Дочерний компонент Profile */}
        <Profile user={this.state.name} />
      </div>
    );
  }
}

Здесь родительский компонент <App> передает свое состояние {name} в виде props своему дочернему компоненту <Profile>.

Дочерний компонент принимает этот пропс следующим образом.

Компонент Profile.js:

const Profile = ({ user }) => {
  return <h1>{user}</h1>;
};

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

Обработка событий снизу вверх через callback

Изменение данных внутри компонентов чаще всего инициируется действиями пользователей (например, кликом кнопки, вводом текста). Чтобы изменить состояние родительного компонента, дочерние элементы используют специальную конструкцию — обработчик события (callback).

Например, рассмотрим форму авторизации.

Родительский компонент LoginForm.js:

import { useState } from 'react';

export default function LoginForm({ onSubmit }) {
  const [username, setUsername] = useState('');
  const handleChange = e => setUsername(e.target.value);

  return (
    <>
      <input type="text" value={username} onChange={handleChange} placeholder="Имя пользователя"/>
      <button onClick={() => onSubmit(username)}>Войти</button>
    </>
  );
}

Основной компонент App.js:

import LoginForm from './LoginForm';

function App() {
  const submitHandler = username => console.log(`Привет ${username}`);

  return (
    <div>
      <LoginForm onSubmit={submitHandler}/>
    </div>
  );
}

Когда пользователь нажимает кнопку «Войти», дочерний компонент отправляет значение имени пользователя обратно в родительский компонент, вызывая предоставленный callback-функционал.

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

JSX

JSX (JavaScript XML) — расширенная версия JavaScript, позволяющая смешивать разметку с кодом. Благодаря этому React-код становится понятнее и легче воспринимается визуально.

Например:

const HelloWorld = () => (
  <div className="container">
    <h1>Привет мир!</h1>
    <p>Это простой пример React-компонента.</p>
  </div>
);

Пример использования компонента:

import React from 'react';

const HelloWorld = () => (
  <div className="container">
    <h1>Привет мир!</h1>
    <p>Это простой пример React-компонента.</p>
  </div>
);

const App = () => {
  return (
    <div className="app-container">
      {/* Использование компонента HelloWorld */}
      <HelloWorld />
      
      {/* Другие элементы интерфейса */
       <button>Кнопка</button>
       <input type="text" placeholder="Введите текст"/>
     }
    </div>
  );
};

export default App;

JSX-код преобразуется в обычный JavaScript во время компиляции.

State and Props

State — внутреннее состояние компонента, которое изменяется в ходе работы приложения. Например, переключатель включен/выключен.

Props — внешние данные, передаваемые компоненту родителями. Они неизменяемые и позволяют управлять поведением компонентов извне.

Благодаря State и Props компоненты становятся динамичными и интерактивными, способными мгновенно реагировать на любые изменения, будь то ввод пользователя или обновление внешних данных. Это отличает их от статичных HTML-элементов, позволяя создавать современные интерфейсы, гибко адаптирующиеся под нужды пользователей.

Пример использования state и props:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment() {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <span>Количество кликов: {this.state.count}</span>
        <button onClick={() => this.increment()}>Кликнуть</button>
      </div>
    );
  }
}

Хуки (Hooks)

Хуки появились в версии React 16.8 и позволили функциональным компонентам использовать такие вещи, как управление состоянием и жизненным циклом компонентов, ранее доступные только классовым компонентам.

Что такое жизненный цикл?

Жизненный цикл компонента — это последовательность этапов, через которые проходит компонент от момента его создания и отображения на экране до удаления из DOM. Основные этапы жизненного цикла включают:

  • Монтирование: Когда компонент впервые добавляется в DOM.

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

  • Размонтирование: Этап, когда компонент удаляется из DOM.

Ранее классовые компоненты могли легко отслеживать и обрабатывать эти этапы благодаря методам жизненного цикла (componentDidMount, componentDidUpdate и др.). Хуки сделали возможным использование аналогичных возможностей в функциональных компонентах, сделав код проще и чище.

Самые распространенные хуки:

  • useState: Управление локальным состоянием компонента.
  • useEffect: Выполнение побочных эффектов (загрузка данных, подписки на события).
  • useContext: Доступ к глобальному состоянию через Context API.

Пример простого счетчика с использованием хуков:

import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      <span>Количество кликов: {count}</span>
      <button onClick={() => setCount(count + 1)}>Кликнуть</button>
    </>
  );
};
export default Counter;

Почему выбирают React?

  • Производительность: Оптимизированная работа с DOM снижает нагрузку на браузер.

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

  • Обширная экосистема: Множество готовых библиотек и инструментов (Redux, Material-UI, Storybook и др.).

  • Популярность: Большая база пользователей, богатое комьюнити и множество учебных материалов.

  • Легкость старта: Небольшой порог входа для новичков, интуитивный подход к созданию компонентов.

Сравнение фреймворков 

Рассмотрим 3 популярных фреймворка: React.js, Vue.js, Angular. 

 

React.js

Vue.js

Angular

Тип

Библиотека

Фреймворк

Фреймворк

Экосистема

Широкая, богата компонентами и инструментами

Умеренная, активно развивающаяся

Полностью интегрированная среда разработки от Google

Поддержка сообществом

Очень высокая, огромное сообщество разработчиков

Высокая, активное комьюнити

Высочайшая, поддерживается корпорацией Google

Производительность

Отличная, благодаря виртуальному DOM и возможности оптимизации производительности вручную

Хорошая, хорошо оптимизирована для небольших проектов

Немного медленнее по сравнению с React и Vue, особенно на больших проектах

Обучение

Легко начать работу, постепенно осваивается глубина библиотеки

Простое начало, гладкая кривая обучения

Сложное начало, требует понимания множества концепций фреймворка

Масштабируемость

Хорошо масштабируется, но требует тщательного планирования архитектуры проекта

Достаточно гибкий и легко расширяемый

Превосходно подходит для крупных приложений благодаря мощному инструментарию и архитектуре

SEO-дружественность

Поддерживает серверный рендеринг SSR, улучшающий SEO

Имеет встроенные инструменты для улучшения SEO

Оптимизирован для сервера, удобен для SEO и поисковых роботов

Популярность

Самый популярный среди фронтенд-разработчиков

Растет популярность, активно используется во многих стартапах и средних компаниях

Высокий уровень популярности, часто выбирается крупными компаниями и корпоративными проектами

Особенности

Компоненты на основе JSX, простая интеграция сторонних библиотек

Гибкость и простоту, двухсторонняя привязка данных

Типизация TypeScript, полная структура приложения, встроенный набор инструментов

Выбор между этими тремя технологиями зависит от конкретных требований проекта. Для нашего небольшого проекта мы будем использовать React.js. Но для сложных корпоративных решений с полным набором инструментов и поддержкой рекомендуется выбирать Angular.

Использование JavaScript vs TypeScript

В нашем интернет-магазине мы будем использовать TypeScript. Так мы сможем быстрее находить и исправлять ошибки, улучшить качество и надежность проекта. В целом, использование TS — общепринятая хорошая практика в современной фронтенд-разработке.

JavaScript:

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

TypeScript:

  • Статически типизированное расширение JavaScript.
  • Обеспечивает проверку типов во время компиляции, снижая вероятность ошибок.
  • Улучшенная читаемость и документированность кода.
  • Более простая интеграция IDE-инструментов (автокомплит, подсказки).

Vite

Vite — современный инструмент сборки фронтенд-проектов. Его отличительные черты:

  • Быстрая разработка благодаря использованию ES-модулей в браузере.
  • Отличается высокой скоростью запуска проекта даже для крупных приложений.
  • Интеграция с популярными библиотеками и фреймворками (например, React, Vue, Svelte).
  • Удобство поддержки Hot Module Replacement (HMR), что улучшает опыт разработки.

Использование Vite значительно ускоряет процесс разработки, сокращает время ожидания между изменениями и отображением результатов в браузере — отличная практика для продуктивной работы над проектами любого масштаба.

Подготовка рабочего пространства

Подготовим наше пространство для работы с Node.js.

Установка Node.js и npm

Чтобы запустить локальную разработку, нужно установить актуальную версию Node.js (рекомендуем v22.14.0 LTS). Вместе с Node.js установится npm — стандартный менеджер пакетов JavaScript.

Для Windows:

Перейдите на официальный сайт nodejs.org и скачайте установщик.

Запустите его и следуйте инструкциям.

Для Linux / MacOS:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
\. "$HOME/.nvm/nvm.sh"
nvm install 22

После установки введите в командной строке:

node -v && npm -v

Убедитесь, что версии Node.js и npm корректно отображаются.

Создание проекта React + TypeScript + Vite

Откройте терминал и введите:

npm create vite@latest online-store -- --template react-ts

Здесь мы создаем Vite-проект и в качестве аргумента указываем, что создаем React -проект с использованием TypeScript.

Переходим в директорию:

cd online-store

И устанавливаем стандартные библиотеки React:

npm install

Помимо стандартной библиотеки React мы будем использовать следующие:

  • MobX + mobx-react-light — для управления состоянием приложения
  • SCSS (Sass) — модульные стили
  • react-router-dom — для маршрутизации по страницам
  • axios — HTTP клиент для работы с API
  • js-cookie — для работы с cookie файлами
  • react-hook-form — для управления формами
  • react-swipeable — для свайпов на мобильном интерфейсе
  • recharts — для построения графиков и диаграмм

Для установки пропишите команду:

npm install axios js-cookie mobx mobx-react-lite react react-dom react-hook-form react-router-dom react-swipeable recharts

Настройка vite.config.ts

Для удобства удалите содержимое файла и напишите следующее:

Импортируем необходимые модули:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import path from 'path'

Настраиваем алиасы для импортов при помощи @.

Пример: import { Button } from "@/shared/ui/button";

export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },

Подключаем плагины и разделяем библиотеки на отдельные чанки:

  plugins: [react()],
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'vendor-react': ['react', 'react-dom', 'react-router-dom'],
          'vendor-mobx': ['mobx', 'mobx-react-lite'],
          'vendor-react-hook-form': ['react-hook-form'],
          'vendor-react-swipeable': ['react-swipeable'],
          'vendor-axios': ['axios'],
          'vendor-js-cookie': ['js-cookie'],
        },

Оптимизируем размер чанка:

        chunkFileNames: 'assets/js/[name]-[hash].js',
        entryFileNames: 'assets/js/[name]-[hash].js',
        assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
      },
    },
  },
})

Мы подключили плагин React SWC для оптимизации сборки путем вывода библиотек в разные чанки для ускорения загрузки и кэширования.

Полный код vite.config.ts:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import path from 'path'
export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  plugins: [react()],
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'vendor-react': ['react', 'react-dom', 'react-router-dom'],
          'vendor-mobx': ['mobx', 'mobx-react-lite'],
          'vendor-react-hook-form': ['react-hook-form'],
          'vendor-react-swipeable': ['react-swipeable'],
          'vendor-axios': ['axios'],
          'vendor-js-cookie': ['js-cookie'],
        },
        chunkFileNames: 'assets/js/[name]-[hash].js',
        entryFileNames: 'assets/js/[name]-[hash].js',
        assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
      },
    },
  },
})

Архитектура и структура проекта

Перед созданием Frontend-части нашего магазина определим структуру проекта:

  • src/shared — общие элементы, используемые по всему проекту:
    • UI-компоненты
    • Иконки
    • Утилиты и функции
    • Хуки
    • Интерфейсы
    • MobX-сторы (API и локальные)
  • src/entities — бизнес-сущности (товары, корзина, заказ и др.) и их компоненты.
  • src/widgets — крупные композиционные блоки (например, шапка сайта, навигация).
  • src/pages — страницы приложения, каждая в отдельной папке с собственным компонентом и стилями.

Переиспользуемые элементы

Разберем элементы, которые используются в нашем проекте.

UI-компоненты (src/shared/ui)

Все файлы в данном разделе мы будем создавать в папке src/shared/ui.

breadcrumbs — «хлебные крошки» для навигации

Image3

Пример breadcrumbs

Breadcrumbs («хлебные крошки») — это элемент интерфейса, который показывает путь от главной страницы сайта до того уровня иерархии, где в текущий момент находится пользователь. 

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

Виды «хлебных крошек»:

  • Иерархические (линейные). Отображают путь от главной страницы через категории и подкатегории к текущей странице. Пример: «Главная → Магазин → Мужская одежда → Футболки → Футболка OnlineStore». 
  • Динамические. Показывают порядок страниц в соответствии с путем пользователя, а не по иерархии на сайте. 
  • Атрибутивные. Отображают не путь по структуре сайта, а набор характеристик текущей страницы. Пример: «Главная → Женская одежда → Новинки → Лен». 
  • С выпадающим списком. Каждый элемент имеет выпадающий список ссылок на смежные категории, который доступен при наведении курсора.

В нашем проекте мы используем иерархическую систему.

Ознакомиться с кодом вы можете в репозитории в папке breadcrumbs (src/shared/ui/breadcrumbs).

button — универсальная кнопка

Мы создадим универсальную кнопку, которую будем подключать на наши страницы.

Пример: 

import React from "react";
    export const Button = ({ children, onClick }) => (
      <button onClick={onClick}>{children}</button>
    );

Обратим внимание на index.module.scss (файл со стилями):

@mixin button {
  position: relative;
  width: 100%;
  border: clamp(1px, 0.2vw, 2px) solid var(--purple);
  padding: clamp(8px, 1.5vw, 12px) clamp(16px, 2vw, 24px);
  height: clamp(32px, 4vw, 38px);
  font-family: 'Open Sans', sans-serif;
  font-size: clamp(12px, 1vw + 0.2rem, 14px);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.2s ease;

В данном куске кода мы создали @mixin (в SCSS) — это директива для объявления миксина. 

Миксин — это блок готовых стилей, которые включаются в другие стили. Он позволяет один раз создать набор CSS-свойств и работать с ними повторно или смешивать с другими значениями

Посмотреть код вы можете в папке button (src/shared/ui/button).

counter — счетчик

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

Ознакомиться с кодом можно в папке counter (src/shared/ui/counter).

dropdown — выпадающий список

Выпадающие списки (dropdown) могут быть разных видов, которые применяются в различных ситуациях. Рассмотрим некоторые из них: стандартный, с мультиселектом, с группировкой или с календарем. 

Стандартный

Представляет список вариантов в компактной форме, позволяет выбрать только один элемент за раз. Применяется для выбора одного варианта из заранее определенного набора вариантов, например, размера, цвета или категории. 

Особенности:

  • Список открывается по нажатию на поле или иконку раскрытия/сворачивания меню.
  • После выбора пункта список закрывается.
  • Ширина выпадающего меню равна ширине поля, длинные пункты списка внутри сокращаются многоточием.

С мультиселектом

Позволяет выбрать несколько вариантов одновременно. Применяется в ситуациях, где нужно выбрать несколько элементов, например:

  • Выбор нескольких предметов для массовых действий;
  • Тегирование элементов с несколькими категориями;
  • Фильтрация результатов поиска.

Особенности:

  • Есть индикатор, показывающий, какие варианты выбраны.
  • Можно использовать опцию «Выбрать все».

С группировкой

Организует варианты в категории или группы. Применяется для больших наборов данных, где элементы естественно попадают в отдельные категории. Примеры:

  • Страны по континентам (Европа, Азия, Африка);
  • Роли на работе по отделам (инженерия, продажи, маркетинг);
  • Продукты по категориям (электроника, мебель, одежда).

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

С календарем

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

Особенности:

  • Для каждой даты отображается соответствующий день недели.
  • Есть возможность перейти к предыдущему или следующему месяцу с помощью кнопок со стрелками.

Ознакомиться с кодом можно в папке dropdown (src/shared/ui/dropdown).

input — поле для ввода

Элемент <input> в HTML позволяет пользователю вводить данные в веб-форму. Он используется внутри тега <form> для декларации элементов управления вводом. 

Назначение элемента: создание разных элементов интерфейса и обеспечение взаимодействия электронной формы с пользователем. В основном <input> предназначен для формирования текстовых полей, кнопок, переключателей и флажков. 

Типы

Некоторые типы элемента <input> и их назначение:

  • Текстовое поле (<input type="text">) — позволяет вводить однострочный текст.
  • Поле для ввода пароля (<input type="password">) — вводимые символы могут отображаться в виде точек или звездочек для скрытия информации.
  • Поле для отправки файлов (<input type="file">) — позволяет загружать файлы с локального компьютера.
  • Флажок (<input type="checkbox">) — позволяет отметить один или несколько вариантов из множества в предоставленном списке.
  • Переключатель (<input type="radio">) — позволяет пользователю выбрать только один вариант из группы.
  • Кнопка отправки (<input type="submit">) — отправляет данные формы на сервер.
  • Поле для ввода электронной почты (<input type="email">) — предназначено для ввода емейла, может проверять, соответствует ли введенное значение формату электронной почты.
  • Поле для ввода номера телефона (<input type="tel">) — предназначено для ввода телефонного номера с возможностью проверки формата.
  • Поле для ввода URL (<input type="url">) — позволяет вводить адрес в интернете.
  • Скрытое поле (<input type="hidden">) — используется для передачи данных, которые не видны пользователю и не изменяются им.

Атрибуты

Атрибуты элемента <input> предназначены для настройки его поведения и в некоторых случаях — внешнего вида элементов формы. Вот некоторые из них и их назначение:

  • id — уникальный идентификатор для элемента, часто используется для связи со скриптом JavaScript.
  • name — имя элемента, используемое при отправке данных формы.
  • value — значение элемента по умолчанию.
  • placeholder — текст-подсказка, отображаемый в пустом поле.
  • required — указывает, что поле обязательно для заполнения.
  • readonly — поле доступно для просмотра, но не для редактирования.
  • disabled — отключает элемент, делая его недоступным для взаимодействия.

Ознакомиться с кодом можно в папке input (src/shared/ui/input).

product-price — отображение цены товара

Данный элемент используется для отображения цены товара в формате:

  • Если у товара есть скидка: старая цена и актуальная цена
  • Если нет скидки: актуальная цена

Ознакомиться с кодом можно в папке product-price (src/shared/ui/product-price).

Иконки (src/shared/icons)

Нам необходимо экспортировать иконки из Figma в формат React (файл .tsx).

Рассмотрим на примере иконки MapPinArea, как его создать

Перейдите в Figma, откройте Frame с иконкой:

Image9

Перейдите на векторный слой:

Image7

Нажмите по векторному слою правой кнопкой мыши и выберите Copy/Paste asCopy as svg:

Image1

В буфер обмена сохранится следующее:

<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path
        d="M10.7502 7.5C10.7502 7.20333 10.8381 6.91332 11.0029 6.66665C11.1678 6.41997 11.402 6.22771 11.6761 6.11418C11.9502 6.00065 12.2518 5.97094 12.5428 6.02882C12.8338 6.0867 13.101 6.22956 13.3108 6.43934C13.5206 6.64912 13.6635 6.91639 13.7213 7.20736C13.7792 7.49834 13.7495 7.79994 13.636 8.07403C13.5224 8.34811 13.3302 8.58238 13.0835 8.7472C12.8368 8.91203 12.5468 9 12.2502 9C11.8523 9 11.4708 8.84196 11.1895 8.56066C10.9082 8.27936 10.7502 7.89782 10.7502 7.5ZM6.25015 7.5C6.25015 5.9087 6.88229 4.38258 8.00751 3.25736C9.13273 2.13214 10.6589 1.5 12.2502 1.5C13.8415 1.5 15.3676 2.13214 16.4928 3.25736C17.618 4.38258 18.2502 5.9087 18.2502 7.5C18.2502 13.1203 12.852 16.2694 12.6252 16.4016C12.5118 16.4663 12.3835 16.5004 12.253 16.5004C12.1224 16.5004 11.9941 16.4663 11.8808 16.4016C11.6483 16.2694 6.25015 13.125 6.25015 7.5ZM7.75015 7.5C7.75015 11.4563 11.1102 14.0822 12.2502 14.8594C13.3892 14.0831 16.7502 11.4563 16.7502 7.5C16.7502 6.30653 16.276 5.16193 15.4321 4.31802C14.5882 3.47411 13.4436 3 12.2502 3C11.0567 3 9.91209 3.47411 9.06817 4.31802C8.22426 5.16193 7.75015 6.30653 7.75015 7.5ZM19.2598 13.8403C19.0752 13.7793 18.8742 13.7924 18.699 13.8768C18.5239 13.9612 18.3884 14.1102 18.321 14.2926C18.2537 14.475 18.2598 14.6764 18.338 14.8543C18.4163 15.0323 18.5605 15.1729 18.7405 15.2466C20.2883 15.8194 21.2502 16.5863 21.2502 17.25C21.2502 18.5025 17.8264 20.25 12.2502 20.25C6.6739 20.25 3.25015 18.5025 3.25015 17.25C3.25015 16.5863 4.21203 15.8194 5.75984 15.2475C5.93976 15.1739 6.08405 15.0332 6.1623 14.8553C6.24055 14.6773 6.24664 14.4759 6.17928 14.2935C6.11193 14.1112 5.9764 13.9621 5.80126 13.8777C5.62612 13.7933 5.42506 13.7803 5.24047 13.8412C2.98953 14.6709 1.75015 15.8822 1.75015 17.25C1.75015 20.1731 7.16047 21.75 12.2502 21.75C17.3398 21.75 22.7502 20.1731 22.7502 17.25C22.7502 15.8822 21.5108 14.6709 19.2598 13.8403Z"
        fill="white"
      />
    </svg>

Изменим значение fill с white на currentColor, чтобы мы могли изменять цвет иконки вместе с темой сайта:

Image4

Добавим конструкцию React:

export const MapPinArea = () => {
  return (
    {{ svg code }}
  }
}

Здесь мы экспортируем константу с svg-кодом. Чтобы было удобно подключать эти иконки в будущем, укажем в имени константы название иконки — в данном случае MapPinArea.

И получаем файл MapPinArea.tsx:

export const MapPinArea = () => {
  return (
    <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path
        d="M10.7502 7.5C10.7502 7.20333 10.8381 6.91332 11.0029 6.66665C11.1678 6.41997 11.402 6.22771 11.6761 6.11418C11.9502 6.00065 12.2518 5.97094 12.5428 6.02882C12.8338 6.0867 13.101 6.22956 13.3108 6.43934C13.5206 6.64912 13.6635 6.91639 13.7213 7.20736C13.7792 7.49834 13.7495 7.79994 13.636 8.07403C13.5224 8.34811 13.3302 8.58238 13.0835 8.7472C12.8368 8.91203 12.5468 9 12.2502 9C11.8523 9 11.4708 8.84196 11.1895 8.56066C10.9082 8.27936 10.7502 7.89782 10.7502 7.5ZM6.25015 7.5C6.25015 5.9087 6.88229 4.38258 8.00751 3.25736C9.13273 2.13214 10.6589 1.5 12.2502 1.5C13.8415 1.5 15.3676 2.13214 16.4928 3.25736C17.618 4.38258 18.2502 5.9087 18.2502 7.5C18.2502 13.1203 12.852 16.2694 12.6252 16.4016C12.5118 16.4663 12.3835 16.5004 12.253 16.5004C12.1224 16.5004 11.9941 16.4663 11.8808 16.4016C11.6483 16.2694 6.25015 13.125 6.25015 7.5ZM7.75015 7.5C7.75015 11.4563 11.1102 14.0822 12.2502 14.8594C13.3892 14.0831 16.7502 11.4563 16.7502 7.5C16.7502 6.30653 16.276 5.16193 15.4321 4.31802C14.5882 3.47411 13.4436 3 12.2502 3C11.0567 3 9.91209 3.47411 9.06817 4.31802C8.22426 5.16193 7.75015 6.30653 7.75015 7.5ZM19.2598 13.8403C19.0752 13.7793 18.8742 13.7924 18.699 13.8768C18.5239 13.9612 18.3884 14.1102 18.321 14.2926C18.2537 14.475 18.2598 14.6764 18.338 14.8543C18.4163 15.0323 18.5605 15.1729 18.7405 15.2466C20.2883 15.8194 21.2502 16.5863 21.2502 17.25C21.2502 18.5025 17.8264 20.25 12.2502 20.25C6.6739 20.25 3.25015 18.5025 3.25015 17.25C3.25015 16.5863 4.21203 15.8194 5.75984 15.2475C5.93976 15.1739 6.08405 15.0332 6.1623 14.8553C6.24055 14.6773 6.24664 14.4759 6.17928 14.2935C6.11193 14.1112 5.9764 13.9621 5.80126 13.8777C5.62612 13.7933 5.42506 13.7803 5.24047 13.8412C2.98953 14.6709 1.75015 15.8822 1.75015 17.25C1.75015 20.1731 7.16047 21.75 12.2502 21.75C17.3398 21.75 22.7502 20.1731 22.7502 17.25C22.7502 15.8822 21.5108 14.6709 19.2598 13.8403Z"
        fill="currentColor"
      />
    </svg>
  )
}

Ознакомиться с кодом остальных иконок можно в папке icons (src/shared/icons).

Функции (src/shared/functions)

Все файлы для функций мы будем создавать в папке src/shared/functions.

calculateDiscount.ts — расчет скидки товара

В этом файле мы будем проводить расчет скидки по формуле: ((oldPrice - currentPrice) / oldPrice) * 100.

isProductAvailable.ts — проверка доступности товара

В этом файле мы проводим проверку на наличие товара по его спецификациям. Рассмотрим фрагменты кода:

  if (!color || !size) {
    // Проверяем все цвета и размеры на наличие хотя бы одного доступного товара
    return Object.values(specifications.color).some(colorSpec =>
      Object.values(colorSpec.size).some(quantity => quantity > 0)
    )
  }

  // Проверяем конкретный цвет и размер
  const colorSpec = specifications.color[color as keyof typeof specifications.color]
  if (!colorSpec) {
    return false
  }

Хуки (src/shared/hooks)

В нашем проекте мы будем использовать один-единственный файл для проверки, является ли человек администратором. 

Данные администратора мы будем хранить в переменной виртуального окружения (.env). Создайте в корне проекта файл .env и придумайте данные для администратора:

VITE_ADMIN_EMAIL=email
VITE_ADMIN_PHONE=phone

Интерфейсы (src/shared/interfaces)

В данной папке мы будем хранить структуру всех данных.

IProduct.ts

Создаем структуру для работы с товаром. В нашей базе данных у товара следующие поля:

  •  _id (тип string)
  • title: (тип string)
  • subtitle: (тип string)
  • article: (тип string)
  • brand: (тип string)
  • oldPrice: (тип number)
  • price: (тип number)
  • path: (тип string[])
  • specifications: (Массив с цветами и размером товара)
  • images: (тип string[])

Order.ts

Создаем структуру для работы с заказами:

Статусы заказа (OrderStatus):

  • Заказ создан
  • Заказ оплачен и подтвержден администратором
  • Заказ успешно отправлен
  • Заказ поступил в город получателя
  • Заказ у курьера
  • Заказ вручен! Спасибо за покупку

Товары в заказе (OrderProduct):

  • id (тип string)
  • specification (Массив с цветами и размером товара)
  • count (тип number)

Структура записи заказа:

  • id (тип string)
  • firstName (тип string)
  • lastName (тип string)
  • email (тип string)
  • phone (тип string)
  • address (тип string)
  • region (тип string)
  • city (тип string)
  • postCode (тип string)
  • products (Массив товаров)
  • status (Массив статусов)
  • price (тип number)
  • company (тип string)

User.ts — структура пользователя

Структура пользователя:

  • id (тип string)
  • firstName (тип string)
  • lastName (тип string)
  • email (тип string)
  • phone (тип number)
  • address (тип string)
  • region (тип string)
  • city (тип string)
  • postCode (тип string)

LinkButton.ts — интерфейс кнопки-ссылки

Интерфейс для кнопки:

  • icon (тип React.ReactNode)
  • path (тип string)
  • title (тип string)

MobX-сторы (src/shared/stores)

Что такое MobX-сторы

MobX-сторы представляют собой специализированные хранилища состояния (state management), применяемые в библиотеках типа MobX для контроля над изменениями данных в приложениях JavaScript. Их основная цель заключается в перемещении бизнес-логики и состояний приложения из отдельных компонентов в централизованные модули, облегчающие тестирование и масштабирование системы. Такие модули полезны как для фронтенд-разработки, так и для серверной части приложений.

Типы MobX-сторов

Существует несколько видов сторов:

  • Глобальные: такие сторы позволяют упростить взаимодействие между различными компонентами приложения. Они хранят общее состояние и обеспечивают обновление UI при изменениях в параметрах. Здесь также удобно размещать универсальные методы вроде API-запросов или обработчиков данных, которые нужны многим компонентам одновременно.

  • Локальные: предназначены исключительно для одного конкретного компонента, предоставляя возможность ограничивать доступ к данным именно этим компонентом. Этот тип удобен, если нужно перенести логику useState за пределы тела компонента, разгружая его кодовую базу.

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

Особенности разработки сторов

При создании сторов в MobX необязательно использовать классы. Библиотека поддерживает написание функций и объектов. Начиная с версии MobX 6, доступна удобная функция makeAutoObservable, позволяющая легко преобразовать обычные объекты в наблюдаемые (observable).

Преимущества использования MobX-сторов

Сторы MobX делают работу разработчиков удобнее:

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

  • Эффективность рендеринга: система оптимизирована таким образом, что обновляются лишь те компоненты, которые реально зависят от конкретных изменений данных, исключая полный перерисовывающий всех элементов страницы.

  • Улучшение архитектуры: вынесение логики за пределы компонента помогает уменьшить сложность компонентов, повышая читаемость и поддерживаемость кода.

Область видимости сторов

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

API-сторы (api/)

Что такое API

API (Application Programming Interface) представляет собой набор правил и протоколов, которые используются для взаимодействия приложений или с внешними сервисами. Это своего рода мост между различными системами и компонентами программного обеспечения, который позволяет обмениваться информацией и функциональностью.

Простым языком, API дает возможность разработчикам интегрировать стороннюю функциональность в свое приложение без необходимости понимания внутренних механизмов реализации другого сервиса

Основные плюсы применения API:

  • Ускорение разработки: Использование готовых решений значительно сокращает сроки разработки приложений. Масштабируемость: Возможность интеграции множества сервисов делает приложения более гибкими и масштабируемыми.

  • Безопасность: API предоставляют механизмы авторизации и защиты данных, ограничивая доступ только необходимым функционалом.

  • Совместимость: Поддержка различных платформ и языков программирования упрощает интеграцию разнородных систем.

Таким образом, API играет ключевую роль в современной разработке ПО, обеспечивая взаимодействие между разными частями системы и способствуя созданию мощных и многофункциональных продуктов.

В нашем проекте базовый адрес API (http://localhost:5001/api) для удобства будет храниться в приватной переменной из файла виртуального окружения (.env). Перейдем в файл .env из каталога проекта и добавим строчку:

VITE_API_URL=http://localhost:5001/api

Где http://localhost:5001/api — базовый путь API.

products — загрузка товаров

Здесь мы создаем две асинхронные функции:

  • Получение всех продуктов.
  • Получение продукта по его уникальному идентификатору. 

Запросы к API мы производим при помощи axios. Код запроса выглядит следующим образом:

Получение всех продуктов:

const response = await axios.get<IProduct[]>(`${this.api}/getallproducts`)

order — работа с заказами

Для работы с заказами создаем четыре асинхронные функции:

  • Создание заказа.
  • Получение всех заказов.
  • Получение активных заказов.
  • Получение заказа по идентификатору.

Запросы к API мы производим при помощи axios. Код запроса выглядит следующим образом:

Получение заказа по id:

const response = await axios.get<IOrder>(`${this.api}/getorderbyid/${id}`)

auth — регистрация, авторизация, проверка пользователя

Здесь мы создаем три асинхронные функции:

  • Получение всех пользователей (getAllUsers.ts)
  • Регистрация
  • Вход

Запросы к API мы производим при помощи axios. Код запроса выглядит следующим образом:

Регистрация пользователя

const response = await axios.post<IUser>(`${this.api}/create`, user)

Мы отправляем POST-запрос на создание пользователя. В прошлой части мы определили следующую структуру тела (body):

{
    "firstName": "Имя",
    "lastName": "Фамилия",
    "email": "example@example.ru",
    "phone": 800000000,
    "address": "Россия, г.Санкт-Петербург, улица Заставская, дом 22, к.2, лит. А, помещ. 303",
    "region" : "Ленинградская область",
    "city": "Санкт-Петербург",
    "postCode": "196006"
}

Локальные сторы (local/)

Для хранения локальных данных мы будем использовать localstorage.

cart — корзина пользователя

Для работы с localstorage мы будем использовать шесть функций:

  • addItem — добавить элемент; передаем id товара, его цвет, размер и количество.
  • removeItem — удалить элемент; передаем id товара.
  • updateItemCount — обновление количество товара; передаем id товара.
  • getItemMaxCount — получение максимального количества товаров; передаем id товара, его цвет и размер.
  • getAvailableQuantity — получение максимально доступного для заказа количества товаров; передаем id товара, его цвет и размер.
  • getTotalPrice — получение общей стоимости корзины. Отметим, что к стоимости заказа мы добавим фиксированную сумму налога (tax).

favorite — избранные товары пользователя

Будем использовать две функции:

  • addItem — добавить элемент; передаем id товара.
  • removeItem — удалить элемент; передаем id товара.

States (states/)

Файл с состоянием мы будем использовать для темы сайта. Если пользователь при первом входе выбрал темную тему, это сохранится в localstorage, и при следующих входах на сайт темная тема установится автоматически.

Бизнес-сущности и их компоненты (src/entities)

В проекте мы используем следующие сущности и компоненты:

  • Товары (product)

    • MainProductBlock — основной блок товара (слайдер, параметры, информация о товаре, рейтинг).

    • ProductInfoBlock — подробная информация (описание, характеристики).

    • UI-компоненты — ImageCarousel, Params (add-to-cart, add-to-favorite), Info, Rates, Description, Header, Specifications.

  • Корзина (cart)

    • CartList — список товаров в корзине.

    • CartBuyBlock — итоговая стоимость, скидки, оформление заказа.

    • Item — отдельный товар в корзине.

  • Оформление заказа (buy)

    • UserInformationForm — форма контактных данных.

    • CardPayBlock — выбор и ввод данных оплаты.

    • CommentInfo — поле для комментария.

  • Главная страница (home)

    • ProductCarousel — слайдер популярных товаров.

    • SeasonalDiscounts — товары с сезонной скидкой.

    • ProductPreview — превью товара.

    • HomeInfo — информация о магазине.

    • HomeBigProduct — баннер с акцентом на товар.

    • HomeProduct — карточки товаров.

  • Избранное (favorite)

    • List — список избранных товаров.

    • Item — отдельный товар в избранном.

  • Прочие сущности

    • order-track — отслеживание заказа (activity, info, progress).
    • admin — аналитика, заказы, пользователи, продукты (отдельные компоненты для админки).

Виджеты (src/widgets/layout)

Создадим два виджета:

  • header
  • navigation

Header

Header (шапка сайта) — это верхняя часть веб-страницы, содержащая важные элементы навигации и бренда. Она играет ключевую роль в структуре и удобстве пользования сайтом. Основные цели header'а включают:

  • Навигация — Шапка помогает пользователям быстро перемещаться между страницами сайта. Обычно здесь размещаются основные разделы меню, такие как главная страница, услуги, контакты и т.п., что облегчает доступ к нужной информации.

  • Брендирование — Header содержит основную информацию о бренде, его логотип и название, что повышает узнаваемость бренда

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

  • Поисковая строка — Многие сайты добавляют в header строку поиска, позволяющую пользователям быстро находить нужную информацию внутри ресурса.

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

В нашем проекте Header выглядит следующим образом в светлой теме:

Image6

А вот так — в темной:

Image2

Navigation

В нашем случае элементы навигации находятся не в Header, поэтому создадим отдельный виджет.

Элементы навигации в нашем проекте выглядят следующим образом:

63fc0bc9 00c2 4a45 B536 Df799ff7d3de

Разделим блок на следующее:

  • Поле для поиска

  • Блок с кнопками основной навигации

Поле для поиска — обычный input, а блок с кнопками мы создадим следующим образом.

Создадим массив с кнопками:

const btns: ILinkButton[] = [
  { title: 'Все категории', path: '/', icon: <CaretDown /> },
  { title: 'Отследить заказ', path: '/order', icon: <MapPinLine /> },
  { title: 'Поддержка', path: '/support', icon: <Headphones /> },
  { title: 'Нужна помощь', path: '/help', icon: <Info /> },
]

И добавим их на страницу при помощи следующего кода:

<div className={`${s.btns} df aic`}>
          {btns.map((b, id) => {
            const isReverse = id === 0 ? s.rowRev : ''
            const isActive = pathname === b.path || (pathname.startsWith('/product') && id === 0)
            if (isActive)
              return (
                <Link to={b.path} className={`${s.active} df ${isReverse ? s.rowRev : ''}`} key={id}>
                  {b.icon} {b.title}
                </Link>
              )
            return (
              <Link to={b.path} className={`df ${isReverse ? s.rowRev : ''}`} key={id}>
                {b.icon} {b.title}
              </Link>
            )
          })}
        </div>

Страницы (pages)

Добавим созданные компоненты на страницы нашего магазина.

Перейдем в папку pages (src/pages). Мы будем создавать 14 страниц.

Страницы пользователя:

  • Главная страница (home)

    • Назначение: Витрина магазина, знакомство с ассортиментом, акциями и новинками.

    • Основные компоненты: ProductCarousel, SeasonalDiscounts, ProductPreview, HomeInfo, HomeBigProduct, HomeProduct.

    • Работа с состоянием: Загрузка товаров через стор products, управление breadcrumbs через стор states.

  • Страница товара (product)

    • Назначение: Подробная информация о товаре, просмотр фото, выбор параметров, добавление в корзину/избранное.

    • Основные компоненты: MainProductBlock, ImageCarousel, Params, Info, Rates, ProductInfoBlock, Description, Header, Specifications.

    • Работа с состоянием: Получение информации о товаре через стор products, breadcrumbs через стор states.

  • Корзина (cart)

    • Назначение: Просмотр и управление товарами в корзине, изменение количества, удаление позиций.

    • Основные компоненты: CartList, CartBuyBlock, Item.

    • Работа с состоянием: Локальный стор cart, breadcrumbs и информация о покупке через стор states.

  • Оформление заказа (buy)

    • Назначение: Ввод контактных данных, выбор способа оплаты, комментарий к заказу, подтверждение заказа.

    • Основные компоненты: UserInformationForm, CardPayBlock, CartBuyBlock, CommentInfo.

    • Работа с состоянием: Breadcrumbs через стор states, список товаров через стор cart.

  • Страница отслеживания заказа (order-track)

    • Назначение: Отслеживание статуса заказа, этапы выполнения, детали и активность.

    • Основные компоненты: MainBlock (activity, info, progress).

    • Работа с состоянием: Получение информации о заказе через стор order.

  • Страница заказа (order)

    • Назначение: Просмотр деталей заказа, статуса, состава и стоимости.

    • Основные компоненты: Информация о заказе, список товаров, итоговая стоимость.

    • Работа с состоянием: Получение информации о заказе через стор order.

  • Избранное (favorite)

    • Назначение: Просмотр всех товаров, добавленных в избранное.

    • Основные компоненты: List, Item.

    • Работа с состоянием: Локальный стор favorite.

  • Авторизация (login)

    • Назначение: Вход пользователя в аккаунт.

    • Основные компоненты: Форма авторизации.

    • Работа с состоянием: Проверка пользователя через стор auth.

  • Регистрация (register)

    • Назначение: Создание нового аккаунта.

    • Основные компоненты: Форма регистрации.

    • Работа с состоянием: Регистрация пользователя через стор auth.

Панель администратора:

  • Главная страница панели администратора (admin-main)

    • Назначение: Панель управления, ключевые показатели.

    • Компоненты: Info (статистика по заказам, товарам).

  • Аналитика (admin-analytics)

    • Назначение: Просмотр графиков и статистики по заказам, пользователям, товарам.

    • Компоненты: OrdersChart, StatsChart.

  • Заказы (admin-orders)

    • Назначение: Список всех заказов, просмотр деталей, изменение статусов.

    • Компоненты: OrderList, OrderFilters, OrderDetails.

  • Товары (admin-products)

    • Назначение: Управление товарами (добавление, редактирование, удаление).

    • Компоненты: ProductList, ProductEditForm.

  • Пользователи (admin-users)

    • Назначение: Список пользователей, их статусы и роли.

    • Компоненты: UserList, UserDetails.

Приложение (app)

В папке app (src/app) находятся два каталога:

  • assets — для хранения базовых значений

  • routes — для определения маршрутов

В папке assets мы храним логотип:

Image5

А также базовые стили приложения, такие как:

  • classes.scss — основные стили для классов. Например .df {display: flex}
  • fonts.scss — шрифты для сайта
  • global.scss — файл для подключения остальных базовых стилей
  • null.scss — обнуление всех значений
  • variables.scss — css переменные для работы с темой сайта

В главном файле main.tsx (src/app/main.tsx) мы подключаем наш маршрутизатор из файла routes/App.tsx и базовый стиль global.scss.

На этом наш магазин готов к использованию. Остался важный шаг: настроим SEO-параметры.

Настройка SEO-параметров

SEO (Search Engine Optimization) — это процесс оптимизации веб-сайта для повышения его видимости в поисковых системах, таких как Google, Яндекс и так далее, путем улучшения позиций сайта в результатах органического поиска. Чем выше позиция сайта в выдаче, тем больше вероятность, что пользователи найдут ваш ресурс и перейдут на него.

Почему SEO важно?

  • Увеличение трафика: Высокое ранжирование в поиске привлекает больше пользователей на сайт, что способствует росту посещаемости и увеличению числа потенциальных клиентов.

  • Повышение узнаваемости бренда: Когда сайт регулярно появляется на первых страницах результатов поиска, это укрепляет доверие к бренду и повышает его авторитетность среди целевой аудитории.

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

  • Конверсии и продажи: Оптимизированный сайт лучше конвертирует посетителей в покупателей или подписчиков благодаря удобному интерфейсу и релевантности содержания запросу пользователя.

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

Таким образом, SEO является ключевым инструментом продвижения бизнеса в интернете, способствующим достижению высоких показателей эффективности и устойчивого роста онлайн-присутствия компании.

Базовые параметры SEO настраиваются в файле index.html (/index.html). Перейдем в него и добавим следующие теги в <head>:

<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Online Store — Онлайн-магазин</title>
 <meta
    name="description"
    content="TimeWebCloud Store — интернет-магазин с лучшими товарами, быстрой доставкой и отличным сервисом."
  />
  <meta name="keywords" content="Online Store, магазин, ecommerce, купить, товары, онлайн, store" />
  <meta name="author" content="Pechenov V.A." />
  <meta name="robots" content="index, follow" />

  <!-- Open Graph -->
  <meta property="og:title" content="Online Store — Онлайн-магазин" />
  <meta
    property="og:description"
    content="Online Store — интернет-магазин с быстрой доставкой и отличным сервисом."
  />
  <meta property="og:type" content="website" />

Мы указали значения заголовка сайта, его описание, ключевые слова, автора, данные robots и данные для Open Graph.

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

Заключение

На этом мы заканчиваем объемную часть рассказа, посвященную фронтенду. Мы создали наше приложение при помощи React, используя связку React + TypeScript + Vite. В следующей части мы опубликуем наш проект в интернет, подключим домен и настроим SSL.

14
40 минут чтения
Средний рейтинг статьи: 5
Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server
Пока нет комментариев