Добавление React приложения в Django

С опытом приходит понимание, что хорошо организованный проект гораздо легче не только в начальной разработке но и в дальнейшей поддержке. Когда каждый файл находится на своём месте и из названия каждой папки и файла в структуре понятно за что он отвечает не только тебе, но и твоим коллегам. Рассмотрим мои изыскания по организации проекта React + Django в одном репозитории.

Определение условий для проекта

Нашими граничными условиями со стороны Django будут:

  • возможность деплоить на продуктив и стейджинг с минимальными изменениями конфигурации от среды разработки
  • среда разработки не должна подразумевать сложной конфигурации. В идеале, всё должно работать через один порт который создаётся через runserver
  • желательна поддержка ASGI для разработки с использованием Websockets
  • гармонично должно вписываться в иерархию файлов Django

Граничные условия со стороны React:

  • работа всего через create-react-app
  • следовательно отсюда — минимальная конфигурация Webpack
  • вся сборка должна выполняться внутри одной папки и не расползаться по Django проекту (это относится к node_modules и результатам сборки в среде разработки)
  • минимальные (а лучше всего нулевые) изменения для работы в продуктиве
  • CI/CD friendly. Система должна без плясок с бубном интегрироваться с системами CI/CD

Эти условия у меня сформировались ещё за время работы со связкой Laravel + React. И для Django хочется сделать как минимум так же, или лучше.

Существующие варианты интеграции Django и React.js

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

Первый. Это создание проекта с помощью create-react-app, затем приложение React запускается своими методами на своём 3000 порту, а Django работает на своём и мы редактируем CSRF заголовки, чтобы браузер не сходил с ума по поводу того что приложение потребляет данные с другого порта.

Второй. Это ручками создаём React проект и настраиваем в нём всё как нам надо руками в конфигурационном файле Webpack.

Оба варианта нам не совсем подходят, каждый по своему. Общего во всех примерах я выловил, что мы используем отдельное приложение Django и внутри мы разворачиваем уже наше React код. Приложение во всех примерах называется frontend. Ну ок, уже хороший старт.

Подготовка установки Django для проверки интеграции

Стандартно разворачиваем Django и добавляем в него DjangoRestFramework. Исходный код финальной версии проекта доступен на GitHub

Создаём приложения для демонстрационных ендпойнтов

Редактируем react_django/settings.py и добавляем строчки в INSTALLED_APPS:

Создаём модель для проверки взаимодействия. Редактируем файл demo_endpoints/models.py

И применяем изменение в базе данных:

Затем прикручиваем нашу модель к DRF. Начинаем с сериализера. Для этого редактируем файл demo_endpoints/serializers.py

Дальше настраиваем вид в файле demo_endpoints/views.py

И настраиваем маршрутеризацию всего нашего проекта в файле react_django/urls.py

И маршрутеризация всего нашего приложения с демонстрационными данными в файле demo_endpoints/urls.py

Проверяем python manage.py runserver и добавляем несколько записей на свой вкус.

Демонстрация работоспособного демо-эндпойнта для проверки интеграции Django и React

Интеграция React

Следующее у нас — это создание Django приложения frontend и установка в него React.

В эту же папку устанавливаем React.js

Нам приходится сделать ещё одну папку с именем frontend, так как create-react-app не позволяет создавать проект в директории где есть ещё файлы. Поэтому после создания переносим вес файлы и удалем лишнюю папку

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

Для продуктивной сборки мы добавим опцию BUILD_PATH. Для этого изменим файл package.json

Для режима разработки нам нужно будет добавить режим «наблюдения» и сборки без запуска сервера в нашу систему.

Для этого создаём папку scripts и складываем в него файл watch.js основа которого взята здесь.

Добавляем в package.json

Интеграция Django

Для отображения файла в продуктиве мы просто настраиваем nginx на нашу папку со статичными файлами и вроде бы всё.

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

Наш проект должен открыться по адресу:

http://127.0.0.1:8000/static/frontend/index.html

Модифицируем файл frontend/src/App.js

Запустим сборку проекта командой yarn watch, перезагрузим страницу и увидим наш работающий эндпойнт

Пример работающего приложения

Итоги проведённой интеграции

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

Из будущих проблем — это поддержка скрипта watch.js, при смене внутренностей react-scripts он может поломаться.

Следующим этапом разработки данной интеграции для меня было бы интересно сделать возможность прокидывать авторизацию из Django в React приложение без пляски с JWT или какими-то другими способами авторизации.

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