CRA,Node.js,Docker中的nginx?

时间:2018-12-14 23:18:46

标签: node.js reactjs docker express create-react-app

我正在开始一个新项目。我目前在根文件夹中有这样的结构:

/app (CRA frontend app) /server (Node.js Express app) Dockerfile docker-compose.yml

我的要求如下:

发展

  • 启动可创建必要容器的Docker
  • 热重装前端React应用程序(使用CRA)
  • 可以为我的React应用提供SSR服务的Node.js服务器(编辑时会自动更新)
  • 可通过http://localhost:3000
  • 访问

生产

  • 可能启动创建必要容器的Docker
  • 创建React应用的生产就绪版本
  • 创建Express应用的生产就绪版本
  • 可通过端口80访问

我现在所在的位置介于一切之间。我不知道如何以正确的方式设置Docker才能使整个工作正常进行,我也不知道在开发时如何构建React应用程序与Express应用程序的结构。一旦我知道如何构造开发部分... + Nginx作为Express应用程序的代理,生产部分似乎会变得更容易。

我目前正在构建一个Docker容器,该容器会在可以进行热重装的情况下启动一个容器,但我不知道如何设置Express部件,以便它们可以很好地协同工作...?

非常感谢您的帮助。

谢谢

1 个答案:

答案 0 :(得分:1)

非常广泛的问题。将其分解为更直接的问题也许更好。无论如何,我认为在Docker中运行您的开发设置并不理想。而是通常使用CRA构建您的应用。然后在Docker中部署。

在我自己的项目中,我有一个运行节点服务器的docker容器,该节点服务器使用SSR为react app提供服务。

这是码头工人部分。请注意,您的package.json应该有一个名为start:prod的脚本才能起作用。然后,该脚本将在生产中启动您的应用程序。

// --- Dockerfile
# Pulled from docker hub and has everything
# needed to run a node project
FROM node:alpine

ENV PORT 3000

# Navigate (cd) to the app folder in the docker container
WORKDIR /usr/src/app

# Copy all package.json / package-lock.json etc. to the root folder
# Executed on build: docker build .
COPY ./package*.json ./

RUN npm i

# copy entire project into docker container
COPY . .

# build front-end with react build scripts and store them in the build folder
RUN npm run build

EXPOSE 3000

CMD ["npm", "run", "start:prod"]

这是将启动服务器的快递服务器。

// -- server.js

import express from "express";
import router from "./controller/index";

const app = express();
const port = 4000;

// Tell the app to use the routes above
app.use(router);

// start the app
app.listen(port, () => {
    console.log(`express running on port ${port}`);
});

这是您需要启动的controller/index.js文件

// -- controller/index.js
import express from "express";
import path from "path";
import serverRenderer from '../middleware/renderer';

const router = express.Router();

// root (/) should always serve our server rendered page
router.use('^/$', serverRenderer());

// other static resources should just be served as they are
router.use(express.static(
    path.resolve(__dirname, '..', '..', 'build'),
    { maxAge: '30d' },
));

export default router;

最后是在服务器上渲染应用程序的渲染器。

// -- renderer.js

import React from "react";
import { renderToString } from "react-dom/server";
import App from "../../src/App";

const path = require("path");
const fs = require("fs");

export default () => (req, res) => {
    // point to html file created by CRA's build tool
    const filePath = path.resolve(__dirname, "..", "..", "build", "index.html");
    fs.readFile(filePath, "utf8", (error, htmlData) => {
        if (error) {
            console.error("error", error);
            return response.status(404).end();
        }

        // render the app as string
        const html = renderToString(<App />);

        // inject rendered app into final html and send
        return res.send(
            htmlData
                .replace('<div id="root"></div>', `<div id="root">${html}</div>`)
        );
    })
}

您将需要bootstrap.js注入对某些软件包的支持。

// -- bootstrap.js
require('ignore-styles');
require('url-loader');
require('file-loader');
require('babel-register')({
    ignore: [/(node_modules)/],
    presets: ['es2015', 'react-app'],
    plugins: [
        'syntax-dynamic-import',
        'dynamic-import-node'
    ]
});

require("./index");

您可以在这里找到所有详细信息: https://blog.mytoori.com/react-served-by-express-running-in-docker-container