65.9K
CodeProject 正在变化。 阅读更多。
Home

将 React 和 Express 部署到 Heroku

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2018 年 5 月 28 日

CPOL

6分钟阅读

viewsIcon

6551

你有一个 React 应用和一个用 Express 或其他技术编写的 API 服务器。现在——如何将它们都部署到服务器上?

你有一个 React 应用和一个用 Express 或其他技术编写的 API 服务器。现在——如何将它们都部署到服务器上?

有几种方法可以做到这一点

  • 将它们放在一起——Express 和 React 文件放在同一台机器上,Express 一肩挑:它负责提供 React 文件,也负责处理 API 请求。
    • 例如,一台运行在 80 端口的 Express 的 DigitalOcean VPS
  • 将它们分开——在一台机器上托管 Express API,在另一台机器上托管 React 应用。
    • 例如,由 Amazon S3 提供服务的 React 应用,由 DigitalOcean VPS 运行的 API 服务器
  • 将 API 放在代理后面——Express 和 React 应用文件放在同一台机器上,但由不同的服务器提供服务
    • 例如,NGINX Web 服务器将 API 请求代理到 API 服务器,并且
      还提供 React 静态文件

本文将介绍如何将它们放在一起。我们将构建 Express 服务器,使其除了提供 API 外,还能提供 React 的静态文件,然后将其部署到 Heroku。Heroku 部署简单,而且入门免费。

创建 Heroku 账户

如果你还没有账户,请访问这里注册。免费的。

安装 Heroku Toolbelt

Heroku 提供了一个名为“toolbelt”的命令行工具。请按照此处的说明进行安装。(在 Mac 上使用 Homebrew,只需运行 brew install heroku)。

应用程序

我们将构建一个密码生成器。每次加载应用或点击“Get More”时,都会生成 5 个随机密码。

Finished product

创建 Express 应用

创建一个父目录来包含所有内容。将其命名为 rando 或你喜欢的任何名称。

$ mkdir rando; cd rando

使用 Yarn 或 NPM 初始化项目

$ yarn init -y
  # or npm init -y

我们需要 2 个包:Express 本身,以及一个 密码生成器。现在安装它们

$ yarn add express password-generator

创建一个名为 index.js 的文件,它将作为 Express 应用,然后输入以下内容

const express = require('express');
const path = require('path');
const generatePassword = require('password-generator');

const app = express();

// Serve static files from the React app
app.use(express.static(path.join(__dirname, 'client/build')));

// Put all API endpoints under '/api'
app.get('/api/passwords', (req, res) => {
  const count = 5;

  // Generate some passwords
  const passwords = Array.from(Array(count).keys()).map(i =>
    generatePassword(12, false)
  )

  // Return them as json
  res.json(passwords);

  console.log(`Sent ${count} passwords`);
});

// The "catchall" handler: for any request that doesn't
// match one above, send back React's index.html file.
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname+'/client/build/index.html'));
});

const port = process.env.PORT || 5000;
app.listen(port);

console.log(`Password generator listening on ${port}`);

我们还需要在 package.json 中添加一个“start”脚本,以便 Heroku 知道如何启动应用。打开 package.json,然后在底部添加一个 scripts 部分。整个文件应该看起来像这样

{
  "name": "rando",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "express": "^4.15.3",
    "password-generator": "^2.1.0"
  },
  "scripts": {
    "start": "node index.js"
  }
}

测试它

一路前进,确保一切正常总是好的。比等到最后才发现什么都行不通要好得多。所以,让我们试试吧。

通过运行以下命令启动 Express 应用

$ yarn start

打开浏览器,访问 https://:5000/api/passwords。你应该会看到类似这样的内容

Password generator working

设置 Heroku

现在我们将应用部署到 Heroku,确保它能正常工作,然后我们将 React 添加进来。

Git Init

Heroku 需要你的项目有一个 Git 仓库,所以我们将创建一个,以及一个 .gitignore 文件来忽略 node_modules,然后提交代码

$ git init
$ echo node_modules > .gitignore
$ git add .
$ git commit -m "Initial commit"

现在我们已准备好部署到 Heroku。运行其 'create' 命令

$ heroku create

你将看到类似这样的内容

Heroku created

为了让它正常工作,我们只需要通过运行以下命令推送代码

$ git push heroku master

它会打印出很多内容,然后应用就会上线。最后几行之一会告诉你应用的 URL

My Heroku URL

现在你可以访问 <your url>/api/passwords 来确保它能正常工作。

太棒了!你已经有一个实时运行在互联网上的应用了!不过它还不是很好用。现在让我们添加一个 React 前端。

创建 React 应用

我们将使用 Create React App 来生成一个项目。还记得我们决定 React 应用将驻留在“client”文件夹中吗?(我们之前在设置 Express 指向“client/build”以获取静态资源时就这么做了)。

如果你还没有安装 Create React App,请先安装

$ yarn global add create-react-app
# or npm install -g create-react-app

在 Express 应用目录中生成 React 应用

$ create-react-app client

如果我们像这样在 package.json 中添加一个“proxy”键,Create React App 将会把 React 应用的 API 请求代理到 Express 应用

"proxy": "https://:5000"

这应该放在 client/package.json 中,而不是 Express 应用的 package.json 中,并且在部署后会被 Heroku 忽略。

打开 src/App.js 并将其替换为以下内容

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  // Initialize state
  state = { passwords: [] }

  // Fetch passwords after first mount
  componentDidMount() {
    this.getPasswords();
  }

  getPasswords = () => {
    // Get the passwords and store them in state
    fetch('/api/passwords')
      .then(res => res.json())
      .then(passwords => this.setState({ passwords }));
  }

  render() {
    const { passwords } = this.state;

    return (
      <div className="App">
        {/* Render the passwords if we have them */}
        {passwords.length ? (
          <div>
            <h1>5 Passwords.</h1>
            <ul className="passwords">
              {/*
                Generally it's bad to use "index" as a key.
                It's ok for this example because there will always
                be the same number of passwords, and they never
                change positions in the array.
              */}
              {passwords.map((password, index) =>
                <li key={index}>
                  {password}
                </li>
              )}
            </ul>
            <button
              className="more"
              onClick={this.getPasswords}>
              Get More
            </button>
          </div>
        ) : (
          // Render a helpful message otherwise
          <div>
            <h1>No passwords :(</h1>
            <button
              className="more"
              onClick={this.getPasswords}>
              Try Again?
            </button>
          </div>
        )}
      </div>
    );
  }
}

export default App;

如果你愿意,也可以更新 CSS(在 src/App.css 中)

.App {
  text-align: center;
  font-family: "Courier New", monospace;
  width: 100%;
}

h1 {
  font-weight: normal;
  font-size: 42px;
}

.passwords {
  list-style: none;
  padding: 0;
  font-size: 32px;
  margin-bottom: 2em;
}

.more {
  font-size: 32px;
  font-family: "Courier New", monospace;
  border: 2px solid #000;
  background-color: #fff;
  padding: 10px 25px;
}
.more:hover {
  background-color: #FDD836;
}
.more:active {
  background-color: #FFEFA9;
}

现在,在 client 文件夹中运行 yarn start 来启动 React 应用。

确保 Express 应用也在运行:同样,在 Express 的文件夹中运行 yarn start

访问 https://:3000,应用应该可以正常工作了!现在我们可以将整个应用部署到 Heroku 了。

部署到 Heroku

当你使用 git push heroku master 命令部署应用时,git 会将所有已提交的文件复制到 Heroku。现在有两个问题

  • 我们需要提交新的 client 代码
  • Express 依赖于 client/build 中的已构建的客户端代码,而我们还没有它,而且我们宁愿不将其提交到 git。

我们将告诉 Heroku 在我们推送代码后构建 React 应用,我们可以通过在顶层(Express 应用的)package.json 中添加一个“heroku-postbuild”脚本来实现这一点。

使用 Yarn

如果你使用 Yarn,脚本看起来像这样

"scripts": {
  "start": "node index.js",
  "heroku-postbuild": "cd client && yarn --production=false && yarn run build"
}

这告诉 Heroku:“嘿,在你完成你正在做的事情后,进入 client 文件夹并构建我的 React 应用。” yarn run build 脚本将启动 Create React App 的生产构建,它会将输出文件放在 client/build 文件夹中,以便 Express 找到它们。

--production=false 标志看起来可能有些奇怪。它之所以存在,是因为默认情况下,yarn 在生产环境中不会安装 devDependencies,而我们需要它们(特别是“react-scripts”),才能构建 React 应用。

做出更改后,将所有内容添加到 git(从顶层 rando 目录运行此命令,而不是在 client 内部)

使用 NPM

如果你使用 NPM,脚本看起来像这样

"scripts": {
  "start": "node index.js",
  "heroku-postbuild": "cd client && npm install --only=dev && npm install && npm run build"
}

这告诉 Heroku:“嘿,在你完成你正在做的事情后,进入 client 文件夹并构建我的 React 应用。” npm run build 脚本将启动 Create React App 的生产构建,它会将输出文件放在 client/build 文件夹中,以便 Express 找到它们。

调用 npm install 两次不是个错误:默认情况下,npm install 会跳过“devDependencies”,但我们需要它们,因为“react-scripts”就在其中,而 npm install --only-dev 命令会安装这些 devDependencies。我们需要生产“dependencies”,所以我们第二次运行 npm install

感谢 Matthew Locke 和 Babajide Ibiayo 在评论中提供了如何让 NPM 工作的方法。

准备部署

剩下的就是提交文件……

$ git add .
$ git commit -m "Ready for awesome"

然后部署应用

$ git push heroku master

它再次打印出你应用的域名。我的域名是 https://glacial-brook-33351.herokuapp.com/。去那里试试吧!

恭喜你,你已经将 React + Express 应用部署到生产环境了 ;)

获取代码

完整的应用可以在 Github 上找到,那里的 README 文件解释了如何部署它。

如果你想使用 NPM,可以查看 npm 分支,运行 git checkout npm。从那里开始,部署会略有不同——运行 git push heroku npm:master 来部署 npm 分支而不是 master 分支。

© . All rights reserved.