在 Heroku 上部署 React 应用和 API 的最佳实践

Posted

技术标签:

【中文标题】在 Heroku 上部署 React 应用和 API 的最佳实践【英文标题】:Best practices to deploy a React app and an API on Heroku 【发布时间】:2020-10-26 07:01:57 【问题描述】:

我目前正在开发一个使用 React(通过 create-react-app)和 JSONServer 作为 API 的项目。

我有一个单一的 Git 存储库,结构如下:

|-- client
|-- api

为了在开发环境中工作,我以 npm start 开头两个文件夹,以便为 React 应用程序提供 http://localhost:3000,为 API 提供 http://localhost:3001。

这样(感谢 Axios)我可以连接到 http://localhost:3001/api 来检索我的内容

import axios from 'axios'

export default axios.create(
  baseURL: 'http://localhost:3001/api'
)

到目前为止一切都很好。

现在我想将我的应用和 API 部署到 Heroku,这就是事情变得复杂的地方。

所以这是我的问题,如果您能就处理问题的最佳方法提供一些建议,将会非常有帮助:

我应该在 Heroku 上创建两个应用程序吗?一个用于客户端,一个用于 API? 如果我在 Heroku 上有两个应用程序,如何从客户端安全地访问 API?可能会获取 API 应用程序的 url(如 https://myapp.herokuapp.com/api),但我必须处理 CORS 问题。 或者我应该只使用 API 创建一个应用程序并将客户端的构建放在同一个文件夹/url (例如:使用 JSONServer 提供构建的公共文件)

目前,我在客户端文件夹的根目录中有一个 server.js 文件和一个带有 web: node server.jsProcfile 来启动构建服务器。然后我使用 Axios 从另一个 Heroku 应用程序(实际上是 API 应用程序)获取数据。

任何建议/帮助将不胜感激!谢谢!

P.S.:这是我的 package.json 和 server.js 文件,用于客户端和 api

客户端的 server.js(位于客户端文件夹的根目录)

const express = require('express')
const http = require('http')
const path = require('path')

const app = express()
app.use(express.static(path.join(__dirname, 'build')))

const port = process.env.PORT || '8080'
app.set('port', port)

const server = http.createServer(app)
server.listen(port, () => console.log(`Running on localhost:$port`))

Api 的 server.js(位于 api 文件夹的根目录)

const express = require('express');
const jsonServer = require('json-server');
const router = express.Router();
const server = jsonServer.create();
const mainRoute = jsonServer.router('db.json');
const middlewares = jsonServer.defaults( noCors: false );
const port = process.env.PORT || 3001;

router.use('/api', mainRoute)
server.use(middlewares);
server.use(router);

server.listen(port);

客户的 package.json:


  "name": "portfolio",
  "version": "0.1.0",
  "private": true,
  "dependencies": 
    "@emotion/core": "^10.0.28",
    "@emotion/styled": "^10.0.27",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "axios": "^0.19.2",
    "express": "^4.17.1",
    "google-spreadsheet": "^3.0.11",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-intl": "^4.6.3",
    "react-lazyload": "^2.6.8",
    "react-router-dom": "^5.2.0",
    "react-scripts": "3.4.1"
  ,
  "scripts": 
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "postinstall": "react-scripts build"
  ,
  "proxy": "https://my-api.herokuapp.com/api",
  "eslintConfig": 
    "extends": "react-app"
  ,
  "browserslist": 
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  ,
  "devDependencies": 
    "eslint-plugin-react": "^7.20.0",
    "react-spring": "^8.0.27",
    "standard": "^14.3.4"
  

Api 的 package.json:


  "name": "json-server-heroku",
  "version": "1.0.0",
  "description": "Simple json-base database to deploy to Heroku",
  "main": "server.js",
  "scripts": 
    "start": "node server.js",
    "dev": "nodemon server.js",
    "fetch": "node fetch-data.js"
  ,
  "keywords": [
    "json-server,heroku, node, REST API"
  ],
  "author": "Jesper Orb",
  "license": "ISC",
  "dependencies": 
    "google-spreadsheet": "^3.0.11",
    "json-server": "^0.16.1"
  

【问题讨论】:

您能否展示您的整个目录结构,以便我们查看您服务器的服务器的server.jspackage.json 文件是在根文件夹中,还是在api 文件夹中? 是的,当然!我将它们添加到帖子中。 所以你没有 package.json 在根级别? api和client里面分别有2个package.json文件对吧? 是的,我每个都有一个 package.json 文件(一个在客户端的文件夹中,一个在 api 的文件夹中)。这两个都在根级别。但是 0 级(存在客户端和 api 文件夹)什么都没有。 如果您只想使用一个 Heroku 应用程序,我可以建议一种方法 【参考方案1】:

我看到你正在使用 json 服务器,所以你不需要使用 express 来服务你的静态资产,而是你需要将你的构建文件夹移动到项目的根级别并将其重命名为 public 以便 json -server 会看到它并根据their markdown on github服务它

    api/package.jsonserver.js 移动到应用程序的根级别。 为了移动您的client/build 文件夹(在从 ./client 运行 npm run build 之后)并将其重命名为 public,添加一个 heroku-postbuild 脚本到根 package.json 像这样 "heroku-postbuild": "cd client && npm install && npm install --only=dev --no-shrinkwrap && npm run build && mv -v build/ .. && cd .. && mv build public" 将您的主要 api url 添加到您的 react 应用程序中

client/.env.development

REACT_APP_BASE_URL=http://localhost:4000/api

client/.env.production

REACT_APP_BASE_URL=https://myapp.herokuapp.com/api
    json-server 自动为您的静态前端文件提供服务。

【讨论】:

感谢您的详尽解释! 嘿,很抱歉再次打扰,但是 Heroku 上的部署很顺利,直到我收到 404 错误(nginx)。它是否与仍在文件夹“api”而不是项目根目录中的文件“server.js”有关? 您采用了哪种方法? 如果您采用第二种方法,您需要为客户端和服务器提供单独的 git 存储库,因为 heroku 一次只能看到一个应用程序 更准确地说,客户端运行良好,但 API 不行。它尝试连接到'localhost/3001/api',我怀疑 Axios 'baseURL' 设置为:'process.env.baseURL || 'localhost:3001/api''

以上是关于在 Heroku 上部署 React 应用和 API 的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

在 Heroku 上部署 React 应用和 API 的最佳实践

在heroku上部署Nodejs+Express+React+Webpack应用

如何将 React 应用程序部署到 Heroku

在 Heroku 上部署 Django API + React 应用程序

如何解决在 Heroku 上部署 React 应用程序时出现的错误

在 Heroku 上部署 react/apollo-server 应用程序