skip to Main Content

I need to serve my React built files (build directory) using nodejs server. With React being wrapped in Docker my nodejs server can not access build directory within /frontend. So what I am thinking of is to move my server.js into /frontend and having a single Dockerfile for both of them.
It would have something like this CMD ['npm run build', 'node server.js']

Would that be illegal and bad practice ?

2

Answers


  1. To architect a web, you have these options:

    Ancient monoliths

    This was the first way to implement a web. All is in the server: frontend & backend. Frontend(html) is created dynamically in the server and sent to the browser on each request.

    In this kind of applications:

    Here some languages and its frameworks

    • java: jsp, jsf, thymeleaf, zk, etc
    • nodejs : ejs, handlebars
    • c# : razor
    • php: wordpress, drupal, etc
    • ruby: almost all frameworks
    • python: django, flask, etc

    Not your case but I saw flows like this:

    • a folder called frontend in the git repository with react, angular , vue, etc
    • perform the build of this folder : npm run build. Usually a human execute this.
    • copy the build result (index.html, js, css etc) to another folder called server in the same git repository

    Modern Monoliths

    • Similar to the previous explained option but automated
    • with modern CSR frameworks like: react, angular & vue
    • a ton of ready to use features like : login

    https://lzomedia.com/blog/different-ways-to-connect-react-frontend-and-node-backend/

    As you can see in the picture, the frontend and backend are deployed n the same server, in the same port.

    If your are developing a single site with its backend, it could work to have frontend and backend in the same repository or directory. It will be like the modern monoliths: mean, mern, mevn with some challenges related to the fact to have different application types in one repository.

    CSR/SPAs with several apis/microservices

    enter image description here

    Suitable if:

    • The company has a dozens of areas, each with complex requirements, unsolvable with just one web application to the entire company
    • web and native mobile version is required with almost the same features
    • integrations (request driven & event driven) between the systems are required
    • decoupled and modern authentication like IAMs or with authorization flows solvable with oauth2

    If this is your case, I advice you a distributed or decoupled architecture. I mean one app or process by repository/server. Here some advantages :

    • frontend (spa) with react
      • own domain like acme.com
      • you could use specialized services for static webs
      • you are not bound to only one api. You could consume several apis.
      • react developers could have its own git strategy
      • custom build for webs
    • backend (api) with nodejs
      • own domain like acme.api.com
      • you could scale only the backend because the heavy process is in this layer
      • nodejs developers could have its own git strategy

    serve the spa

    If your web is simple, you could use

    But if your web has complexities like backend: env variables portability, one build, etc you could use:

    References

    Login or Signup to reply.
  2. You can’t (*) run multiple servers in a single container.

    For your setup, though, you don’t need multiple servers. You can compile the React application to static files and serve those from your other application. There are some more advanced approaches where a server injects the data or a rendered copy of the page as it serves these up; these won’t necessarily work with a React dev server in a separate container (probably some of the setup described in @JRichardsz’s answer goes into this more).

    If both halves are in the same repository, you can potentially use a Docker multi-stage build to compile the front-end application to static files, then copy the result into the main server image. This could look like:

    # Build the frontend.
    FROM node:lts AS frontend
    WORKDIR /app
    COPY frontend/package*.json ./
    RUN npm ci
    COPY frontend/ ./
    RUN npm build
    # Built files are left in /app/build; this stage has no CMD.
    
    # Build the main server.
    FROM node:lts
    WORKDIR /app
    COPY server/package*.json ./
    RUN npm ci
    COPY server/ ./
    # Copy the build tree from the frontend image into this one.
    COPY --from=frontend /app/build ./static
    RUN npm build
    
    # Normal metadata to set up and run the server container.
    EXPOSE 3000
    CMD ["npm", "run", "start"]
    

    (*) It’s technically possible, but you need to install some sort of process manager, which adds significant complication. It’s less of a concern with the approach I describe here but you also lose some things like the ability to see just a single process’s logs or the ability to update only one part of the system without restarting the rest of it. The CMD you suggest won’t do it. I’d almost always use multiple containers over trying to shoehorn in something like supervisord.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search