mapbiz
    Preparing search index...

    mapbiz

    Содержание

    1. Иерархия
    2. Стек
    3. Подход
    4. Старт
    5. Orval и генерация типов
    6. Деплой

    Иерархия папок

    • /src
      • /app - Страницы/Лейтауты и прочий стафф next.js
      • /public -
        • /icons - Иконки для svgr
        • /img - Фотки
        • /video - Видео
      • /components -
        • /ИмяКомпонента
          • index.tsx - Файл компонента
          • presentation.tsx - Необязательный Файл презентации (верстки), если он требуется
          • container.tsx - Необязательный Файл контейнера (логика), если он требуется
          • style/.modules/.scss - Необязательный Файл стилей, если такой требуется. Исключительный ситуации, компановкой и мерджем стилей занимается cva
      • /actions - Серверный actions для next, выносить сюда по такой логике:
        • Сущность/НазваниеСервиса/ЧастиПриложения.ts
      • /hooks - Папка кастомных хуков для проекта
      • /context - Папка для контекстов react, в ней же стоит делать Provider, и маленькие useХуки, которые используют контекст, если логика более сложная, то useХуки, стоит выносить /hooks
      • /data - Файлы с общими данными в них лучше хранить, ссылки в футере, телефоны и прочее
      • /types - .d.ts файлы проекта, глобальные типы В НИХ НЕ МОЖЕТ БЫТЬ ИМПРОТА ТИПОВ
        • global.d.ts - Файл общеге редеклера
      • /styles - Общие стили проекта, то есть сюда будут помещены стили которые используются глобальное по проекту
        • _typography.scss - Настройка типографии по проекту, классы (классы с размерами текста, шириной отступов и т.д) Импортирован глобально через addictionalData
        • /mixins - Миксины scss для упрощения стилей Необязательный
          • _mixins.scss - Точка обьядинения. В него импротированы все миксины для использования Необязательный
        • /functions - Функции scss Необязательный
          • _functions.scss - Точка обьядинения. В него импортированы все функции для использования Необязательный

    Стек

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

    Подход к разработке

    От такого вида компонента стоит отталкиваться

    // Типизация пропсов
    interface Props {}

    // Стили
    const styles = cva();

    // Сам код компонента
    export default function Component({}: Props) {}

    Представим такую ситуацию, нам нужно сделать некие компонент Test и зависимый TestText, и мы не можем создать стрелочный FC компонент внутри файла компонента Test. Что делать в такой ситуации? Обратиться к соглашению о именовании.

    • Test
      • файлы компонента
    • TestText
      • файлы компонента

    То есть такой взаимосвязанные компонент, будет именоваться так НазваниеКорневогоКомпонентаНазваниеВзаимосвязанногоКомпонента.

    Когда могут наступить подобные ситуации?

    1. У нас есть серверный компонент Test и нам нужно создать клиентский компонент внутри него, тогда мы обратимся к соглашению и создадим TestText как зависимый компонент и сделаем его клиентским
    2. Если случай исключительный то при помощи @description опишите этот случай, чтобы не происходило путаницы

    Так как весь react построен фактически на функциях, то функциональные паттерны стоит использовать вместе с ним. К примеру паттерн HOC, фактически является паттерном Функция высшего порядка/HOF. Поэтому думаю применение паттерна частичное применение является неплохим способом организации кода. Сам паттерн крайне простой, перейдем к примерам
    Представим у нас есть некий компонент Header и Button, на нужно создать ButtonHeader, а в есть варианты Button - primary, secondary, dark.
    Вариант dark нам подходит, применяется от аналогичным пропсом, код будет выглядеть так

      import Button from "@components/Button";

    // Частичное применение. Мы зарезервировали конкретные параметры/пропсы
    const ButtonHeader: FC = () => <Button dark className="styles" />

    export default function Header() {
    return (
    <header>
    <ButtonHeader />
    </header>
    )

    }

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

    • Разбиение на FC
      К примеру, нам нужно вывести подкомпонент (То есть компонент локальный и связанный с тем где мы создаем).

        // Стили относятся к HeaderLogo
      const styleHeaderLogo = cva()
      const HeaderLogo: FC = () => <div className={stylesLogo()}></div>

      // Стили относятся к Header
      const styles = cva();
      export default function Header() {
      return (
      <header className={styles()}>
      <HeaderLogo />
      </header>
      )
      }
    • Вариантное разбиение
      К примеру в нашей ситуации, нам не нужно создавать отдельный FC для подкомпонента, но скомпоновать стили требуется тогда мы используем возможности cva variants

      const styles = cva("base styles", {
      variants: {
      intent: {
      headerLogo: "styles-header-logo"
      },
      },
      });
      export default function Header() {
      return <header className={styles()}>
      <div className={styles({ intent: 'headerLogo' })}></div>
      </header>
      }

    ПРИМЕРЫ БАЗОВЫЕ ЧТОБЫ ОТ НИХ ОТТАЛКИВАТЬСЯ

    Сложным будет назван такой компонент в котором и верстка и логика крайне обьемные и умещая их в один файл, получается огромное неконтролируемое количество кода. В таком случае стоит использовать паттерн Container/Presentational паттерну, разделяя компонент на 2 файла -

    • presentation.tsx - Верстка и небольшие части логики (к примеру условная отрисовка в зависимости от пропа)
      Пример:
    export default function Item({ someBooleanProp = false, someArrayProp = [] }) {
    return (
    <div>
    {someBooleanProp && "true"}
    {someArrayProp.map((item, i) => (
    <span key={i}>{item}</span>
    ))}
    </div>
    );
    }

    То есть, небольшая условная отрисовка тут есть, перебор туда же, но сложной логики с помощью useState, useEffect и прочего нет

    • container.tsx - Логика компонента, он принимает в себя presentation и работает с логикой прокидывая данные ему в пропсы, такой компонент зачастую клиентский.
      Пример:
    import Item from "./presentation.tsx"

    export default ItemContainer() {
    const [someData, setSomeData] = useState([]);

    useEffect(() => {
    // Сложная логика обработки при монтировании
    }, [])

    return (
    <Item someArrayProp={someData} someBooleanProp={someData.length > 0}></Item>
    )
    }

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

    • index.ts - Компонент для экспорта
    import Item from "./container.tsx";

    export default Item;

    Бывают ситуации в next когда нужно передать начальные данные из серверного компонента в клиентский в таком случае, не стоит создавать presentation.tsx, а обойтись только container.tsx + ИмяКомпонента.tsx и использовать container.tsx в серверном окружении

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

    Старт

    dev

      npm i
    npm run generate:env-types # Генерация типов env для typescript
    npm run dev

    production

      npm i
    npm run generate:env-types # Генерация типов env для typescript
    npm run build
    npm run start

    Orval и генерация типов api

    Orval - Генератор типов из schema.yml/json от openApi. Позволяет быстро генерировать библиотеку типов и функций запроса к апи.

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

    Так как, Orval в проекте применяется как генератор типов для typescript, а библиотека запросов самописная, такая ситуация сломает типы только для нее, но если такая потребность все же создалась (к примеру были добавлены новые компоненты)

      npm run regenerate:api-types # Регенерация апи типов
    

    СМЕНА ТИПОВ У МОДЕЛЕЙ МАЛОВЕРОЯТНА В КОНЦЕ РАЗРАБОТКИ БЕКЭНДА, ПОТОМУ ЧТО МОДЕЛИ БАЗЫ НЕ ЧАСТО НУЖНО МЕНЯТЬ
    В СЛУЧАЕ ЕСЛИ РЕГЕНЕРАЦИЯ НЕОБХОДИМА СТОИТ УБЕДИТЬСЯ В ТОМ ЧТО СТАРЫЕ УЖЕ СГЕНЕРИРОВАННЫЕ ТИПЫ НЕ УДАЛЕНЫ

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

    Если требуется посмотреть доку по типам, то

    Сначала сгенерируйте доку

      npm run genereate:doc-types
    

    После запустите

      npm run start:doc-types
    

    Деплой

    manual -

      cp .env.example .env # Заполните .env
    npm i
    npm run build
    npm run start

    docker -

      cp .env.example .env.docker # Заполните .env специфичный для Docker, не забывая о standalone
    npm i # Необязательно, чтобы ускорить билд докера и сгенирировать lock файл
    docker-compose up -d # Старт docker-compose'a