3

I have directories for node and react like this:

Project
 + client
   + admin
      + build
          + index.html
 + server_api
   + server.js
   + Dockerfile
 
 + docker-compose.yml

docker-compose file

  server_api:
    container_name: speed_react_server_api
    build:
        context: ./server_api
        dockerfile: Dockerfile
    image: speed_react/server_api
    ports:
        - "5000:5000"
    volumes:
        - ./server_api:/usr/src/app

My server.js serve static file from react app like this:

app.get('*', (req, res) => {
    res.sendFile(path.resolve(__dirname, '../client/admin/', 'build', 'index.html'));
});

But it seems that it is not working. I do not want to move folder client to server

Can you suggest me solution?

2 Answers 2

1

You can rearrange files as needed in your Dockerfile.

Note that this will require removing the volumes: line that (probably) causes your entire Dockerfile to get mostly ignored. Your Docker container won't be usable as a development environment. A host Node is very easy to install and features like live reloading and interactive debugging will work much better with much less configuration and tuning required.

If you move the Dockerfile up to the root directory, it can access both directory trees. Then you can use a multi-stage build to build the client and then copy it into the server. That would roughly look like this:

FROM node:14 AS client
WORKDIR /app
COPY client/package.json client/yarn.lock .
RUN yarn install
COPY client .
RUN yarn build

FROM node:14
WORKDIR /app
COPY server_api/package.json server_api/yarn.lock .
RUN yarn install
COPY server_api .
COPY --from=client /app/admin/build admin  # <-----
EXPOSE 5000
CMD ["node", "index.js"]

In your code, change the path to path.resolve(__dirname, 'admin', 'index.html'); it should match the destination inside the container filesystem of the COPY --from=client line.

In your host development environment, you can use a symbolic link to point at the files (on MacOS or Linux)

ln -s ../client/admin/build admin

Finally, you need to change your docker-compose.yml to point at the root directory as the build context, and remove the bind mount (which will have a dangling symlink and not the file content).

server_api:
  build: .
  image: speed_react/server_api
  ports:
    - "5000:5000"
Sign up to request clarification or add additional context in comments.

Comments

1

Update:

One answer is given by @David, that best to build the Docker image with multi-stage.

The other way is to build the only API and as the client has no dependency and so you can just mount clinet with API.

  server_api:
    container_name: speed_react_server_api
    image: abc
    ports:
        - "4001:4001"
    entrypoint: sh -c "cd /usr/src/app/server_api/; node server.js"
    volumes:
        - ./server_api/:/usr/src/app/server_api/
        - ./client/:/usr/src/app/client/ 

You did not mention the error but I assume the script not serving the distribution.

But seems like you are missing express-static-files configuration.

To serve static files such as images, CSS files, and JavaScript files, use the >express.static built-in middleware function in Express.

The function signature is:

express.static(root, [options])

Here is the complete script

const express = require('express');
const path = require('path');
const app = express();
const PORT=process.env.PORT | 4001
app.use(express.static('../client/admin/build/dist', {
  maxAge: '31557600' 
}))

var compress = require('compression');
app.use(compress()); 

app.use('/', express.static('../client/admin/build/dist/', { redirect: false }));

app.get('*', (req, res) => {
  res.sendFile(path.resolve('../client/admin/build/dist/index.html'));
});

app.listen(PORT, () => {
  console.log(`Incentive frontend is listening on ${PORT}`);
});

2 Comments

Thanks for your answer but You might misunderstood my question. Due to react app is not in folder of Dockerfile so server.js cannot read it. I want a solution for this. If react app in folder of node, it is running well.
oh got it, one answer was in mind already give by @David, updating answer for another approch.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.