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

4

我目前正在使用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.:这是我客户端和API的package.json文件和server.js文件

客户端的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服务器.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文件夹内部。 - onuriltan
好的,没问题!我已经把它们添加到帖子中了。 - user990463
所以你在根目录下没有package.json文件?api和client文件夹里分别有2个package.json文件,是这样吗? - onuriltan
是的,我为每个文件夹(客户端文件夹和 API 文件夹)都有一个 package.json 文件。这两个文件都在根目录下。但是在级别 0(客户端和 API 文件夹所在的位置)没有任何文件。 - user990463
是的,那是正确的。 - user990463
显示剩余3条评论
1个回答

6

我看到你正在使用json服务器,因此你不需要使用express来提供静态文件,在项目的根目录下移动build文件夹并将其重命名为public,以便json-server可以按照他们在github上的markdown说明进行服务。

  1. api/package.jsonserver.js移动到应用程序的根目录。
  2. 为了移动client/build文件夹(从./client运行npm run build后)并将其重命名为public,请在根package.json中添加heroku-postbuild脚本,如下所示:"heroku-postbuild": "cd client && npm install && npm install --only=dev --no-shrinkwrap && npm run build && mv -v build/ .. && cd .. && mv build public"
  3. 将主API网址添加到您的React应用程序中,如下所示:

client/.env.development

REACT_APP_BASE_URL=http://localhost:4000/api

client/.env.production

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

1
感谢您提供如此详尽的解释! - user990463
嘿,很抱歉再次打扰,但在Heroku上的部署一切都很顺利,直到我遇到了404错误(nginx)。这是否与文件“server.js”有关,该文件仍位于文件夹“api”中而不是项目的根目录中? - user990463
如果您采用第二种方法,则需要为客户端和服务器分别创建git存储库,因为Heroku一次只能看到一个应用程序。 - onuriltan
1
更准确地说,客户端运行良好,但API不行。它试图连接到“localhost/3001/api”,我怀疑是Axios的“baseURL”设置为:“process.env.baseURL || 'http://localhost:3001/api'”。 - user990463
让我们在聊天中继续这个讨论 - onuriltan
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接