在生产中使用 docker 的 create-react-app 使用不同的 API URL 的最佳方法是什么?

MGL*_*don 6 docker reactjs docker-compose create-react-app

好吧,我一整天都在绞尽脑汁,但仍然找不到一个优雅的解决方案。我创建了一个 React 应用程序,它对后端的 Django 服务器进行一些 API 调用。我创建了一个 settings.js 文件,该文件根据应用程序是在开发中还是在生产中运行来更改 API url。settings.js 文件如下所示:

let API_SERVER_VAL = '';
let MEDIA_SERVER_VAL = '';
let FRONTEND_SERVER_VAL = ''; 

switch (process.env.NODE_ENV) {
    case 'development':
        API_SERVER_VAL = 'http://localhost:8000';
        MEDIA_SERVER_VAL = 'http://localhost:8000';
        FRONTEND_SERVER_VAL = 'http://localhost:3000';
        break;
    case 'production':
        API_SERVER_VAL = process.env.API_SERVER;
        MEDIA_SERVER_VAL = process.env.API_SERVER;
        FRONTEND_SERVER_VAL = process.env.API_SERVER;
        break;
    default:
        API_SERVER_VAL = 'http://localhost:8000';
        MEDIA_SERVER_VAL = 'http://localhost:8000';
        FRONTEND_SERVER_VAL = 'http://localhost:3000';
        break;
}

export const API_SERVER = API_SERVER_VAL;
export const MEDIA_SERVER = MEDIA_SERVER_VAL;
export const FRONTEND_SERVER = FRONTEND_SERVER_VAL;

export const SESSION_DURATION = 5*3600*1000;
Run Code Online (Sandbox Code Playgroud)

基于上述的示例 API 如下所示:

import * as settings from '../../settings';
....
axios.post(`${settings.API_SERVER}/api/auth/logout/`, ...)
Run Code Online (Sandbox Code Playgroud)

Dockerfile 如下所示。我正在执行图像的两阶段构建。

###########
# BUILDER #
###########

# pull official base image
FROM node:12.18.3-alpine3.9 as builder

# set work directory
WORKDIR /usr/src/app

# install dependencies and avoid `node-gyp rebuild` errors
COPY package.json .
RUN apk add --no-cache --virtual .gyp \
        python \
        make \
        g++ \
    && npm install \
    && apk del .gyp

# copy our react project
COPY . .

# perform npm build
ARG API_SERVER
ENV API_SERVER=${API_SERVER}
RUN API_SERVER=${API_SERVER} \ 
  npm run build

#########
# FINAL #
#########

# pull official base image
FROM node:12.18.3-alpine3.9 

# set work directory
WORKDIR /usr/src/app

# install serve - deployment static server suggested by official create-react-app
RUN npm install -g serve

# copy our build files from our builder stage
COPY --from=builder /usr/src/app/build ./build
Run Code Online (Sandbox Code Playgroud)

docker-compose 文件如下所示(react 服务)。基本上,docker-compose React 服务将一个名为 API_SERVER=127.0.0.1 的参数传递到 Dockerfile 的构建器阶段。

version: "3.7"

services:
  django:
    build:
      context: ./backend/app
      dockerfile: Dockerfile.prod
    command: gunicorn mainapp.wsgi:application --bind 0.0.0.0:8000
    volumes:
      - django_static_volume:/usr/src/app/files_static
      - app_media_volume:/usr/src/app/files_media
    expose:
      - 8000
    # ports:
    #   - 8000:8000
    env_file:
      - ./backend/.env.prod
    depends_on:
      - db
  db:
    image: postgres:12.0-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    env_file:
      - ./backend/.env.prod.db
  react:
    build:
      context: ./frontend/app
      dockerfile: Dockerfile.prod
      args: 
          - API_SERVER=127.0.0.1 
    volumes:
      - react_static_volume:/usr/src/app/build/static
    expose:
      - 3000
    command: serve -s build -l 3000
    depends_on:
      - django
  nginx:
    restart: always
    build: ./nginx
    volumes:
      - django_static_volume:/usr/src/app/django_files/static
      - app_media_volume:/usr/src/app/media
      - react_static_volume:/usr/src/app/react_files/static
    ports:
      - 80:80
      # - 8000:80
    depends_on:
      - react

volumes:
  postgres_data:
  django_static_volume:
  app_media_volume:
  react_static_volume:
Run Code Online (Sandbox Code Playgroud)

我还在通过在主页的控制台中打印它来检查此 settings.API_SERVER 是否已从 docker 正确传递。所以在 Home.js 中我有以下内容:

console.log(`The environment is ${process.env.NODE_ENV}`);
console.log(`The API server is ${process.env.API_SERVER}`);
console.log(`The settings API server is ${settings.API_SERVER}`);
console.log(`The PUBLIC URL is ${process.env.PUBLIC_URL}`);
Run Code Online (Sandbox Code Playgroud)

但是,我在控制台中看到了这一点。 在此输入图像描述

所以只有 process.env.NODE_ENV 被正确显示!我认为这是因为这显示了图像第二阶段而不是构建器阶段的环境变量。

我究竟做错了什么?不需要额外的 npm-packages 来解决这个问题最优雅的方法是什么?

MGL*_*don 5

我实际上从create-react-app的官方页面找到了答案。问题是 create-react-app 不会获取环境变量,除非它以REACT_APP_. 这是这里所说的:

注意:您必须创建以 REACT_APP_. 除此以外的任何其他变量NODE_ENV都将被忽略,以避免意外暴露机器上可能具有相同名称的私钥。更改任何环境变量都将要求您重新启动正在运行的开发服务器。

这正是我能够process.env.NODE_ENV在控制台中打印出来但不能打印其他变量的原因,因为它们不是以REACT_APP_.

所以我将 Dockerfile 更改为:

# perform npm build
ARG API_SERVER
ENV REACT_APP_API_SERVER=${API_SERVER}
RUN REACT_APP_API_SERVER=${API_SERVER} \ 
  npm run build 
Run Code Online (Sandbox Code Playgroud)

并且,settings.js 包含:

case 'production':
    API_SERVER_VAL = process.env.REACT_APP_API_SERVER;
    MEDIA_SERVER_VAL = process.env.REACT_APP_API_SERVER;
    FRONTEND_SERVER_VAL = process.env.REACT_APP_API_SERVER;
    break;
Run Code Online (Sandbox Code Playgroud)

控制台现在打印出我从 docker-compose.yaml 文件传递​​的所有内容!