file structure:
.
├── .editorconfig
├── .gitignore
├── backend
│ ├── .babelrc
│ ├── package.json
│ ├── README.md
│ ├── server.js
│ └── yarn.lock
├── Dockerfile
├── frontend
│ ├── .gitignore
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── README.md
│ ├── src
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── components
│ │ │ ├── ClientCounter.js
│ │ │ └── ServerMessage.js
│ │ ├── connection.js
│ │ ├── index.js
│ │ ├── logo.svg
│ │ ├── reportWebVitals.js
│ │ └── setupTests.js
│ └── yarn.lock
└── package.json
- add a script at the project's root that install packages in frontend and backend with the option
--freeze-lockfile
- add a script that runs the
build
command in./frontend
- add a script that runs the
deploy
command in./backend
{
...
"scripts": {
...
"install:prod": "cd frontend && yarn install --freeze-lockfile && cd ../backend && yarn install --freeze-lockfile",
"build": "cd frontend && yarn build",
"deploy": "cd backend && yarn deploy"
},
...
}
process.env.NODE_ENV
equals to "production"
when running yarn build
(react-scripts build
)
import axios from "axios";
const API_ROOT =
process.env.NODE_ENV === "production"
? "/api"
: "http://localhost:4000/api";
export const api = axios.create({ baseURL: API_ROOT });
The default path of the output folder for react-scripts build
is ./frontend/build
.
import path from "path";
import express from "express";
import cors from "cors";
const app = express();
if (process.env.NODE_ENV === "production") {
const __dirname = path.resolve();
app.use(express.static(path.join(__dirname, "../frontend", "build")));
app.get("/*", function (req, res) {
res.sendFile(path.join(__dirname, "../frontend", "build", "index.html"));
});
}
if (process.env.NODE_ENV === "development") {
app.use(cors());
}
FROM node:16-alpine
EXPOSE 4000
COPY . /app
WORKDIR /app
RUN corepack enable
RUN yarn install:prod
RUN yarn build
CMD ["yarn", "deploy"]