1

I have a sample application with razzle, react and typescript. I am trying to dockerize it and run it as a container, but although the container runs, the static files are empty.

This is my Dockerfile

FROM node:alpine
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

ENV NODE_ENV production
ENV RAZZLE_CUSTOM_VARIABLE xxxxx

COPY package.json .

RUN npm install --production

COPY build ./build

EXPOSE 3000

CMD [ "node", "build/server.js" ]

I create the image with docker build --tag=my-app:0.0.1 .

I get the following warning (not sure if related to my issue):

SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.

And finally I run my container with for example: docker run -p 3001:3000 my-app:0.0.1 and it executes properly.

When I go to localhost:30001 I can see my react application but without styles. For example, I can see a http://localhost:3003/static/css/bundle.b1e53d9a.css is being served, but it's empty also the http://localhost:3003/static/js/bundle.fd36658a.js is empty and that must be the issue. The question is Why?

If I do a node build/server.js locally on my filesystem I can see the served react app on localhost:30001 working properly with styles.

Am I missing something or doing something wrong?

I am way too new with docker and node js to figure it out myself.

UPDATE 1: In case it's needed this is my package.json

{
  "name": "llevatelo-web",
  "version": "0.1.0",
  "license": "MIT",
  "scripts": {
    "start": "razzle start",
    "build": "razzle build",
    "test": "razzle test --env=jsdom",
    "start:prod": "NODE_ENV=production node build/server.js"
  },
  "dependencies": {
    "express": "4.17.1",
    "razzle": "3.0.0",
    "react": "16.9.0",
    "react-dom": "16.9.0",
    "react-router-dom": "5.0.1"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^4.0.0",
    "@testing-library/react": "^8.0.9",
    "@types/express": "^4.17.0",
    "@types/jest": "^24.0.17",
    "@types/react": "^16.9.0",
    "@types/react-dom": "^16.8.5",
    "@types/react-router-dom": "^4.3.4",
    "@types/webpack-env": "^1.14.0",
    "eslint": "^6.1.0",
    "razzle-plugin-typescript": "^3.0.0",
    "ts-jest": "^24.0.2",
    "typescript": "^3.5.3"
  },
  "jest": {
    "transform": {
      "\\.(ts|tsx)$": "ts-jest",
      "\\.css$": "<rootDir>/node_modules/razzle/config/jest/cssTransform.js",
      "^(?!.*\\.(js|jsx|css|json)$)": "<rootDir>/node_modules/razzle/config/jest/fileTransform.js"
    },
    "testMatch": [
      "<rootDir>/src/**/__tests__/**/*.(ts|js)?(x)",
      "<rootDir>/src/**/?(*.)(spec|test).(ts|js)?(x)"
    ],
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "json"
    ],
    "collectCoverageFrom": [
      "src/**/*.{js,jsx,ts,tsx}"
    ]
  }
}

diegosasw
  • 13,734
  • 16
  • 95
  • 159

1 Answers1

3

You should build your app on the image instead of building it on windows and copying it.

You can optimize the size later with multi stage builds

Full Dockerfile :

FROM node:alpine as builder
RUN mkdir -p /app
WORKDIR /app
ENV NODE_ENV production

COPY package.json ./
RUN npm install --production

COPY src ./src
COPY public ./public
RUN npm run build


FROM node:alpine
RUN mkdir -p /app
WORKDIR /app
ENV NODE_ENV production

COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/build ./build

EXPOSE 3000

CMD [ "node", "build/server.js" ]

With the multi stage build, the image size drops from 290MB to 267MB for the razzle sample app.

Fully tested on windows, assets are served correctly.

Gabriel Bleu
  • 9,703
  • 2
  • 30
  • 43
  • Why is building the app in Windows and copying a bad practice? I've just realised that building everything in the image forces me to have all dependencies (even the @types) available at the image, so there's no point to split devDependencies anymore. – diegosasw Aug 14 '19 at 09:55
  • 1
    Because node can have platform specific dependencies and windows handle file permissions differently. That's the purpose of multi stage build, you can have dev dependencies on builder and remove them on final image. – Gabriel Bleu Aug 14 '19 at 10:06
  • Excellent, then I guess I should aim to build the app on the same platform it will be run later on, or have Dockerfile multi-stage do all the work. Thanks. – diegosasw Aug 14 '19 at 10:31