Создание профессионального React-приложения

При разработке приложения React (предположим, что мы используем create-react-app) следует обратить внимание на каталоги, которые при этом создаются. При запуске npm run build будет создана папка сборки, в которой располагается оптимизированная статичная версия приложения.

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

→ build
  → static
    → css
      → css files
    → js
      → js files
    → media
      → media files
  → index.html
  → other files...
Содержание

Маршрутизация на стороне клиента с React

Библиотека React Router использует метод pushState . То, что делает pushState, представляется довольно интересным. Например, при навигации (использовании Link или маршрутизатора React) со страницы https://css-tricks.com на страницу https://css-tricks.com/archives/ в адресной строке отобразиться https://css-tricks.com/archives//. Но это не заставит браузер загрузить page /archives или даже проверить ее наличие.

В сочетании с компонентной моделью React позволяет изменять маршруты при отображении различных страниц, основанных на тех же маршрутах Что же происходит потом, когда мы пересылаем код на реальный сервер? В документации это хорошо расписано:

Если вы пользуетесь маршрутизаторами с HTML5 pushState history API (например, React Router с browserHistory), то многие серверы со статичными файлами выдадут ошибку.

При этом каждому серверу требуется индивидуальная настройка. Например, для Express требуется такая:

app.get('*', (req, res) => {
  res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});

Но это предполагает размещение create-react-app в корне сервера, который использует подстановочный символ (*). Он отвечает на все запросы маршрута, обрабатывая файл index.html в папке сборки, которая находится в корне серверного приложения. В этом случае у нас была бы следующая структура папки (при условии, что серверная часть выполнена в NodeJS):

→ Server 
  → Client (куда идет ваш код react)
    → build (это папка сборки, после того, как вы запустите npm run build)
    → src
    → node_modules
    → package.json
    → другие файлы и папки интерфейса
  → Другие файлы и папки сервера

Мой внешний (create-react-app) и внутренний интерфейс (ASP.NET) были разными проектами. Поэтому обслуживание статичных файлов с помощью навигации по директории было невозможно. Но поскольку мы разворачиваем статичное приложение, нам не нужна серверная часть.

Во время своего исследования, я обнаружил, что при настройке Azure требуется файл конфигурации в папке wwwroot. И в структуре папок ASP.NET тоже присутствует папка wwwroot. Она спрятана где-то в Azure. Я не могу это показать без развертывания create-react-app..

Начало работы со службой приложений в Microsoft Azure

Для начала воспользуйтесь бесплатной учетной записью на сервисе и затем направляйтесь в портал Azure.

  1. Направляйтесь по такому пути: All services→ Web → App Services
  2. Добавьте новое приложение, дайте ему имя, оформите подписку и создайте группу ресурсов. Затем кликните по кнопке «Создать».Создаем новую службу приложений на портале Azure.
  3. Затем вы должны получить уведомление о создании ресурса. Мы его увидим только когда нажмем на кнопку «Обновить». Далее кликните по имени нового созданного приложения. В данном случае АzureReactDemo2. Отображение служб приложения на портале Azure.
  4. В меню слева находится все, что необходимо для управления приложением (обзор, журнал активности, центр развертывания…)

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

Демонстрация различных элементов службы приложений в Azure CLI.

Приложение запущено и работает.

Мы создали новую службу приложений. Но мы еще не загрузили свой код в Azure – содержимое папки сборки React. Поэтому займемся этим и установим приложение React.

Локальная работа

Нам необходимо создать новое приложение React и установить react-router  как зависимость.

npx create-react-app azure-react-demo
cd azure-react-demo

А также уставить react-router  (на самом деле, react-router-dom).

npm i react-router-dom

Запуская приложение с npm start, мы должны получить страницу по умолчанию.

Вид страницы по умолчанию, созданной в React.

Для тестирования маршрутизации необходимо создать несколько страниц. Я изменил локальную версию и загрузил ее на GitHub. Надеюсь, что вы сможете справиться с react и react-router. Тут можно скачать демоверсию.

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

Вид папки и файлы в измененном приложении create-react-app.

Код измененных файлов, входящих в состав проекта:

// App.js
import React, { Component } from "react";
import "./App.css";
import Home from "./pages/Home";
import Page1 from "./pages/Page1";
import Page2 from "./pages/Page2";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

class App extends Component {
  render() {
    return (
      <Router>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/page1" component={Page1} />
          <Route path="/page2" component={Page2} />
        </Switch>
      </Router>
    );
  }
}

export default App;
// Page1.js
import React from "react";
import { Link } from "react-router-dom";

const Page1 = () => {
  return (
    <div className="page page1">
      <div className="flagTop" />
      <div className="flagCenter">
        <h1 className="country">Argentina (PAGE 1)</h1>
        <div className="otherLinks">
          <Link to="/page2">Nigeria</Link>
          <Link to="/">Home</Link>
        </div>
      </div>
      <div className="flagBottom" />
    </div>
  );
};

export default Page1;
// Page2.js
import React from "react";
import { Link } from "react-router-dom";

const Page2 = () => {
  return (
    <div className="page page2">
      <div className="flagTop" />
      <div className="flagCenter">
        <h1 className="country">Nigeria (PAGE 2)</h1>
        <div className="otherLinks">
          <Link to="/page1">Argentina</Link>
          <Link to="/">Home</Link>
        </div>
      </div>
      <div className="flagBottom" />
    </div>
  );
};

export default Page2;
/* App.css */
html {
  box-sizing: border-box;
}

body {
  margin: 0;
}

.page {
  display: grid;
  grid-template-rows: repeat(3, 1fr);
  height: 100vh;
}

.page1 .flagTop,
.page1 .flagBottom {
  background-color: blue;
}

.page2 .flagTop,
.page2 .flagBottom {
  background-color: green;
}

.flagCenter {
  display: flex;
  align-items: center;
  flex-direction: column;
  justify-content: center;
  text-align: center;
}

.page a {
  border: 2px solid currentColor;
  font-weight: bold;
  margin: 0 30px;
  padding: 5px;
  text-decoration: none;
  text-transform: uppercase;
}

.flags {
  display: flex;
  width: 100%;
}

.flags > .page {
  flex: 1;
}

Запущенное приложение работает локально. Поэтому маршрутизаторы срабатывают при клике на links и даже при обновлении страницы.

Развертывание приложения в Azure

Загрузим приложение в Azure. Для этого необходимо выполнить несколько шагов.

Шаг 1: переходим в центр развертывания (Deployment Center)

Находясь в Azure, переходим в центр развертывания (Deployment Center). Для этого мы будем использовать Local Git для управления версиями и Kudu для Build Provider.

Не забывайте нажимать на кнопку «Продолжить» или «Завершить» после выбора параметра.

Центр развертывания Azure и выбор системы управления версиями.

Вид на раздел Build Provider в Центре развертывания Azure.

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

Запрос учетных данных для развертывания службы приложений на портале Azure.

После внесения изменений, в React-приложение нужно создать сборку для производства. Нам необходимо сообщить Kudu, какую версию движок Node мы будем использовать. Иначе процесс завершится сбоем. Для этого нужно добавить Node в файл package.json. Я пользуюсь версией 10.0.

К сожалению, нельзя просто взять и добавить то, что мы хотим. У Azure есть собственный список поддерживаемых версий Node. Для проверки версии запустите az webapp list-runtimes в интерфейсе командной строки. Затем необходимую версию узла в файл package.json:

"engines": {
  "node": "10.0"
}	

Список сред выполнения в Azure в интерпретаторе командной строки Azure CLI.

Шаг 2: сборка приложения

Для сборки приложения давайте запустим npm build в Terminal.

Шаг 3: инициализация репозитария Git

Перейдите в папку сборки и инициализируйте репозитарий Git. Адрес для клонирования репозитария показан на странице обзора. В зависимости от учетных данных, которые вы используете (для приложения или для пользователя) вид страницы будет несколько отличаться.

Вид службы приложений в Azure и адрес для клонирования репозитария Git.

git init
git add .
git commit -m "Initial Commit"
git remote add azure <git clone url>
git push azure master

Теперь идем в работающее  приложение, используя URL-адрес, указанный на странице обзора. Приложение выдаст ошибку 404 при обновлении /page2. Так как мы попытались загрузить страницу с сервера  с использованием маршрутизации на стороне клиента. Но страница вообще не должна была быть получена сервером.

Ошибка при запросе страницы.

Настройка Azure для согласования клиентской и серверной маршрутизации

Добавим в общую папку XML- файл web.config следующего содержания:

<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="React Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Но если вы не отформатируете приведенный выше код XML, эффекта от этого файла не будет. Вы можете скачать средства форматирования XML для вашего текстового редактора. Для For VSCode, это будет плагин XML Tools.

XML-файл в VSCode.

На этом этапе приложение можно собрать заново, хотя при этом потеряется информация Git в папке сборки. Нет необходимости каждый раз запускать npm run build. Так как начинается процесс «непрерывного» развертывания.

Заключение

Можно много говорить об Azure и о том, так много он позволяет сделать. Например, настройку маршрутизации на стороне клиента и сервера. А для этого у нас есть все необходимое.

Данная публикация представляет собой перевод статьи «Deploying a Client-Side Rendered create-react-app to Microsoft Azure» , подготовленной дружной командой проекта Интернет-технологии.ру