Полное руководство по Remix. Часть 1

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!



Привет, друзья!


В этой серии статей я расскажу вам о Remix — новом фреймворке для создания клиент-серверных веб-приложений на JavaScript (точнее, на React) со встроенной поддержкой TypeScript.


Remix позволяет разрабатывать так называемые PESPA (Progressive Enhancement Single Page Apps — одностраничные приложения с возможностью прогрессивного улучшения). Это означает следующее:


  • почти весь код приложения "живет" на сервере;
  • приложение остается функциональным даже при отсутствии JS;
  • JS используется только для прогрессивного улучшения UX (User Experience — пользовательский опыт).

Подробнее о PESPA и других архитектурах веб-приложений можно почитать здесь.


Очевидно, что разработчики Remix вдохновлялись Next.js и Svelte.


К слову, здесь вы найдете полное руководство по Next.js.


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


Это часть номер раз.


Содержание


  • Маршрутизация / Routing
  • Ресурсные роуты / Resource Routes
  • Интерфейс роутов / API Routes
  • Бэкенд для фронтенда / Backend for Frontend
  • Загрузка данных / Data Loading
  • Запись данных / Data Writes
  • Оптимистичное обновление UI / Optimistic UI
  • Ограничения модулей / Module Constraints
  • Обработка ошибок / Error Handling
  • Обработка ошибки 404 / Not Found Handling
  • Переменные среды окружения / Environment Variables
  • Стилизация / Styling
  • TypeScript

Маршрутизация / Routing


Маршрутизация (роутинг) — это, пожалуй, самая важная концепция в Remix. Все начинается с маршрутов (роутов): компилятор, первоначальный запрос документа и почти все последующие действия пользователя.


Начнем с определения понятий:


  • вложенные роуты (nested routes) — связь (map) роутов с сегментами URL обеспечивает соответствие URL определенным компонентам и данным, известным перед рендерингом страницы;
  • URL — полный путь в поисковой строке браузера пользователя. Один URL может совпадать (соответствовать — match) с несколькими роутами. Обратите внимание: роут и URL — разные вещи в Remix;
  • роут (route) или модуль роута (route module) — модуль JS с определенными экспортами (loader, action, default function (компонент) и др.), который соответствует одному или нескольким сегментам URL. Поскольку роут соответствует сегменту URL, по одному пути могут рендерится несколько модулей. Иерархия компонентов соответствует сегментам URL (в основном);
  • путь (path) или путь роута (route path) — сегмент URL, которому соответствует отдельный модуль. Путь роута определяется названием файла в директории app/routes;
  • родительский макет (parent layout route) или родительский роут (parent route) — модуль, который рендерит макет для дочерних компонентов через компонент Outlet;
  • макет без пути (pathless layout route) или роут без пути (pathless route) — модуль, который не добавляет сегменты к URL, но добавляет компонент в иерархию UI (User Interface — пользовательский интерфейс) при совпадении его дочерних роутов;
  • дочерний роут (child route) — модуль, который рендерится внутри родительского Outlet при совпадении его пути с URL;
  • индексный роут (index route) — модуль, который имеет такой же путь, как его родительский роут, но рендерится в качестве дефолтного дочернего роута внутри Outlet;
  • динамический сегмент (dynamic segment) — сегмент пути роута, извлекаемый из URL и передаваемый в приложение, такой как идентификатор (ID) записи или слаг (slug) поста;
  • сплат (splat) — замыкающая звездочка (trailing wildcard) в пути роута, который благодаря этому совпадает со всеми сегментами URL (включая последующий /);
  • аутлет (outlet) — компонент, который рендерится внутри родительского модуля, предназначенный для рендеринга дочерних модулей. Другими словами, аутлет определяет локацию дочерних роутов.

Вложенный роутинг


Вложенный роутинг — это связь между сегментами URL и иерархией компонентов в UI. Сегменты URL определяют:


  • макеты, формирующие страницу;
  • загрузку JS-кода, используемого на странице;
  • загрузку данных, используемых на странице.

Определение роутов


Роуты определяются посредством создания файлов в директории app/routes. Вот как может выглядеть иерархия роутов приложения:


app
├── root.jsx
└── routes
    ├── accounts.jsx
    ├── dashboard.jsx
    ├── expenses.jsx
    ├── index.jsx
    ├── reports.jsx
    ├── sales
    │   ├── customers.jsx
    │   ├── deposits.jsx
    │   ├── index.jsx
    │   ├── invoices
    │   │   ├── $invoiceId.jsx
    │   │   └── index.jsx
    │   ├── invoices.jsx
    │   └── subscriptions.jsx
    └── sales.jsx

  • root.jsx — это корневой роут, служащий макетом для всего приложения. Другие роуты рендерятся внутри его Outlet;
  • обратите внимание на файлы, названия которых совпадают с названиями директорий, в которых эти файлы находятся. Эти файлы предназначены для формирования иерархии макетов компонентов. Например, sales.jsx — это родительский роут для всех дочерних роутов внутри директории app/routes/sales. При совпадении с URL любого роута из этой директории, он будет рендерится внутри Outlet модуля sales.jsx;
  • роут index.jsx будет рендерится внутри Outlet при совпадении URL с путем директории (например, пути example.com/sales соответствует роут app/routes/sales/index.jsx).

Рендеринг иерархии макета роута


Предположим, что URL имеет вид /sales/invoices/123. С этим URL будут совпадать следующие роуты:


  • root.jsx;
  • routes/sales.jsx;
  • routes/sales/invoices.jsx;
  • routes/sales/invoices/$invoiceId.jsx.

При посещении этой страницы пользователем Remix отрендерит такую иерархию компонентов:


<Root>
  <Sales>
    <Invoices>
      <InvoiceId />
    </Invoices>
  </Sales>
</Root>

Иерархия компонентов полностью соответствует иерархии файлов в директории app/routes:


app
├── root.jsx
└── routes
    ├── sales
    │   ├── invoices
    │   │   └── $invoiceId.jsx
    │   └── invoices.jsx
    ├── sales.jsx
    └── accounts.jsx

Иерархия компонентов для URL /accounts будет такой:


<Root>
  <Accounts />
</Root>

Для рендеринга дочерних роутов внутри родительского используется Outlet. root.jsx рендерит основной макет, боковую панель и аутлет для дочерних роутов:


import { Outlet } from "@remix-run/react";

export default function Root() {
  return (
    <Document>
      <Sidebar />
      {/* ! */}
      <Outlet />
    </Document>
  );
}

В свою очередь, sales.jsx рендерит аутлет для всех его дочерних роутов (app/routes/sales/*):


import { Outlet } from "@remix-run/react";

export default function Sales() {
  return (
    <div>
      <h1>Sales</h1>
      <SalesNav />
      {/* ! */}
      <Outlet />
    </div>
  );
}

Индексные роуты


Индексный роут — это дефолтный дочерний роут. При отсутствии других дочерних роутов рендерится индексный модуль. Например, URL exmaple.com/sales соответствует индексный роут app/routes/sales/index.jsx.


Индексные роуты не должны рендерить дочерние модули, они являются тупиком для URL. Например, вместо рендеринга глобальной панели навигации в app/routes/index.jsx, ее следует рендерить в app/root.jsx.


Параметр строки запроса ?index


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


└── app
    ├── root.jsx
    └── routes
        ├── sales
        │   ├── invoices
        │   │   └── index.jsx
        │   └── invoices.jsx

Какому роуту будет соответствовать путь /sales/invoices? Роуту /sales/invoices.jsx или роуту /sales/invoices/index.jsx? Ответ: роуту /sales/invoices.jsx. Для совпадения с роутом /sales/invoices/index.jsx путь должен заканчиваться параметром строки запроса ?index:


└── app
    ├── root.jsx
    └── routes
        ├── sales
        │   ├── invoices
        │   │   └── index.jsx   <-- /sales/invoices?index
        │   └── invoices.jsx    <-- /sales/invoices

В некоторых случаях добавление ?index происходит автоматически (например, при отправке формы в индексном или его родительском роуте), в других — это делается вручную (например, при использовании fetcher.submit() или fetcher.load()).


Вложенные URL без вложенных макетов


Иногда может потребоваться добавить вложенный URL без добавления компонента в иерархию UI. Рассмотрим страницу редактирования счета:


  • мы хотим, чтобы URL имел вид /sales/invoices/$invoiceId/edit;
  • мы хотим, чтобы соответствующий компонент был прямым потомком корневого компонента.

Другими словами, мы не хотим этого:


<Root>
  <Sales>
    <Invoices>
      <InvoiceId>
        <EditInvoice />
      </InvoiceId>
    </Invoices>
  </Sales>
</Root>

Мы хотим это:


<Root>
  <EditInvoice />
</Root>

Для создания плоской иерархии UI используется плоское название файла — использование . в названии файла позволяет добавлять сегменты URL без добавления компонентов в иерархию UI:


└── app
    ├── root.jsx
    └── routes
        ├── sales
        │   ├── invoices
        │   │   └── $invoiceId.jsx
        │   └── invoices.jsx
        ├── sales.invoices.$invoiceId.edit.jsx 						
Источник: https://habr.com/ru/company/timeweb/blog/717156/


Интересные статьи

Интересные статьи

Привет, друзья! Представляю вашему вниманию перевод второй части серии статей, посвященных паттернам проектирования в TypeScript. Спасибо Денису Улесову за помощь в переводе материала. Паттерны...
Эти заметки могут быть полезны для инженеров находящихся в самом начале карьеры, когда стоит выбор, где себя применить, с чего начать и каким путем пойти начиная карьеру инженера программиста.Мой цель...
Это четвертая и финальная часть из серии моих публикаций, посвященных вопросу ввоза обедненного гексафторида урана (ОГФУ) из Европы в Россию. Первая посвящена технологиям обогащения у...
Итак, в предыдущем посте мы занимались кодированием «живого» видео формата H.264 на Android устройстве, которое затем отправляли для просмотра на персональный компьютер под виндой. ...
Дешёвый сервер из китайских запчастей. Часть 1, железная Размытая кошка позирует на фоне настраиваемого сервера. На заднем плане – мышка на сервере Привет, Хабр! В жизни каждого человека ино...