Вопрос или проблема
Я создал базовый API на Rails 7 с фронтендом на React, используя Vite. Проект также был создан с помощью:
npm create vite@latest
команды, если это полезно для понимания контекста. Проблема, с которой я сталкиваюсь, заключается в том, что приложение работает нормально локально, но компоненты/маршруты не отображаются на Heroku.
Приложение использует React Router для обработки маршрутизации, поэтому я понимаю, что это вызовет проблему с тем, что маршруты не отображаются так, как ожидалось через Heroku, из-за того, что контент рендерится на стороне клиента. Я пытался решить это с помощью Nginx buildpack для Heroku.
Тем не менее, мне не удается успешно отобразить мои компоненты после развертывания, несмотря на то, что я настроил NodeJS, Ruby и Nginx buildpack (в этом порядке) и следовал множеству похожих постов здесь:
-
https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-nginx
-
Как развернуть фронтенд на React + бэкенд API на Rails с nginx, capistrano и passenger
-
https://gist.github.com/huangzhuolin/24f73163e3670b1cd327f2b357fd456a
Вот некоторые скриншоты и файлы для справки:
Структура файлов
Снова, это приложение было настроено с помощью команды Vite выше, так что эта структура предоставлена из коробки.
Похоже, что Heroku может искать мой файл vite.config.js в каталоге /app/frontend/ вместо каталога /frontend/ на основе логов Heroku:
Package.json
{
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@fontsource/roboto": "^5.1.0",
"@mui/icons-material": "^6.1.1",
"@mui/material": "^6.1.1",
"@mui/styles": "^6.1.1",
"@mui/x-data-grid": "^7.18.0",
"@mui/x-date-pickers": "^7.18.0",
"axios": "^1.7.7",
"dayjs": "^1.11.13",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.2"
},
"devDependencies": {
"@eslint/js": "^9.9.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^9.9.0",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0",
"vite": "^5.4.1"
}
}
nginx.conf.erb
daemon off;
# У Heroku dynos минимум 4 ядра.
worker_processes <%= ENV['NGINX_WORKERS'] || 4 %>;
events {
use epoll;
accept_mutex on;
worker_connections <%= ENV['NGINX_WORKER_CONNECTIONS'] || 1024 %>;
}
http {
gzip on;
gzip_comp_level 2;
gzip_min_length 512;
gzip_proxied any; # маршрутизатор Heroku отправляет заголовок Via
server_tokens off;
log_format l2met 'measure#nginx.service=$request_time request_id=$http_x_request_id';
access_log <%= ENV['NGINX_ACCESS_LOG_PATH'] || 'logs/nginx/access.log' %> l2met;
error_log <%= ENV['NGINX_ERROR_LOG_PATH'] || 'logs/nginx/error.log' %>;
include mime.types;
default_type application/octet-stream;
sendfile on;
# Необходимо прочитать тело за 5 секунд.
client_body_timeout 5;
upstream app_server {
server unix:/tmp/nginx.socket fail_timeout=0;
}
server {
listen <%= ENV["PORT"] %>;
server_name _;
keepalive_timeout 5;
location / {
# Раскомментируйте это условие, чтобы принудительно использовать SSL/перенаправить http -> https
# if ($http_x_forwarded_proto != "https") {
# return 301 https://$host$request_uri;
# }
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
}
vite.json
{
"all": {
"sourceCodeDir": "frontend",
"watchAdditionalPaths": []
},
"development": {
"autoBuild": true,
"publicOutputDir": "vite-dev",
"port": 3036
},
"test": {
"autoBuild": true,
"publicOutputDir": "vite-test",
"port": 3037
}
}
vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': {
target: 'https://fake.herokuapp.com/', // Раскомментируйте эту строку при развертывании на Heroku
// target: 'http://localhost:3000', // Раскомментируйте эту строку при разработке локально - Замените на ваш URL API Rails
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
})
Буду признателен за любые советы!
Ответ или решение
Для развертывания вашего приложения на Heroku с использованием Rails 7 API и React-фронтенда, созданного с помощью Vite, выполните следующие шаги. Я постараюсь подробно объяснить, как правильно настроить среду, чтобы всё работало корректно.
Шаг 1: Настройка папки проекта
Убедитесь, что структура вашего проекта соответствует ожидаемой. Ваша папка должна выглядеть примерно так:
/app
/frontend
/src
vite.config.js
package.json
/RailsBackend
...
Где /frontend
– это ваша папка с Vite-приложением. Важно, чтобы все настройки ссылались на правильные директории.
Шаг 2: Конфигурация Nginx
Вы правильно настраиваете Nginx для проксирования запросов. В вашем nginx.conf.erb
добавьте следующие строки, чтобы обеспечить поддержку маршрутизации для вашего React-приложения. Это позволит выполнять корректную маршрутизацию на стороне клиента.
location / {
try_files $uri $uri/ /index.html;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
Шаг 3: Настройка npm и Vite
Убедитесь, что у вас установлен правильный скрипт сборки для деплоя. В вашем package.json
нужно убедиться, что вы выполняете команду сборки:
"scripts": {
"dev": "vite",
"build": "vite build",
"start": "vite preview" // Добавьте эту строку
}
Шаг 4: Конфигурация Heroku
-
Добавление buildpack-ов: Убедитесь, что вы добавили Node.js, Ruby и Nginx buildpacks в правильном порядке.
heroku buildpacks:add --index 1 heroku/nodejs heroku buildpacks:add --index 2 heroku/ruby heroku buildpacks:add --index 3 https://github.com/heroku/heroku-buildpack-nginx
-
Настройка переменных среды: Убедитесь, что у вас правильно настроены переменные окружения. Обычно вам нужно добавить переменные, такие как
RAILS_ENV
иNODE_ENV
, чтобы убедиться, что во время сборки используется правильная конфигурация.heroku config:set RAILS_ENV=production NODE_ENV=production
Шаг 5: Сборка приложения
После внесения всех изменений выполните сборку вашего Vite приложения и деплой на Heroku:
git add .
git commit -m "Configure deployment for Heroku"
git push heroku main
Шаг 6: Логи и отладка
Если после развертывания возникли проблемы с отображением компонентов или маршрутизации, вам следует проверить логи Heroku:
heroku logs --tail
Это может дать представление о том, что именно идет не так. Обратите внимание на сообщения об ошибках и убедитесь, что все зависимости были правильно установлены.
Шаг 7: Проверка выполнения
После успешного развертывания перейдите на свой Heroku URL, чтобы убедиться, что приложение работает как предполагалось. Попробуйте изменить маршруты, чтобы подтвердить, что компоненты рендерятся правильно.
Заключение
Если после выполнения всех шагов у вас все еще возникают проблемы, возможно, стоит проверить конфигурацию вашего маршрутизатора в React, особенно в случае, если вы используете динамические пути. Убедитесь, что ваше приложение правильно обрабатывает 404 ошибки и маршрутизацию на стороне клиента. В случае дополнительных вопросов не стесняйтесь обращаться к сообществу или документации Heroku.