Answer a question

I have a react project with Webpack which I'm trying to dockerize it following this article.

Dockerfile:

FROM node:12.14.1

RUN npm install webpack -g

WORKDIR /tmp
COPY package.json /tmp/
RUN npm config set registry http://registry.npmjs.org/ && npm install

WORKDIR /usr/app
COPY . /usr/app/
RUN cp -a /tmp/node_modules /usr/app/

RUN webpack

ENV NODE_ENV=production
ENV PORT=4000

CMD [ "/usr/local/bin/node", "--experimental-modules", "./src/index.js" ]

EXPOSE 4000

docker-compose.yml:

ex_dashboard:
  build: .
  ports:
  - "80:4000"
  volumes:
  - .:/usr/app/:rw
  environment:
  - NODE_ENV=dev
  command: >
    sh -c '
      if test -d node_modules; 
      then 
        echo node_modules_exists ; 
      else 
        cp -a /tmp/node_modules /usr/app/dashboard; 
      fi && 
      npm install && 
      /usr/local/bin/node --experimental-modules ./src/index.js
    '

When I run docker-compose up, everything goes well until I encounter this error:

ex_dashboard_1  | (node:18) ExperimentalWarning: The ESM module loader is experimental.
ex_dashboard_1  | file:///usr/app/src/index.js:9
ex_dashboard_1  |   <Provider store={store}>
ex_dashboard_1  |   ^
ex_dashboard_1  | 
ex_dashboard_1  | SyntaxError: Unexpected token '<'
ex_dashboard_1  |     at Loader.moduleStrategy (internal/modules/esm/translators.js:66:18)
ex_dashboard_1  |     at async link (internal/modules/esm/module_job.js:37:21)

The whole project works well if I just run it by npm start or build it by npm run build. But I don't know why this happens in docker container.

Here is package.json:

{
  "name": "explore_dashboard",
  "version": "1.0.0",
  "description": "A dashboard for the Explore project",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "cross-env NODE_ENV=development webpack-dev-server --hot",
    "build": "cross-env NODE_ENV=production webpack",
    "lint": "eslint ./src",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://gitlab.basalam.dev/data/explore_dashboard.git"
  },
  "author": "Gh.Sherafati",
  "license": "ISC",
  "resolve": {
    "alias": {
      "react-dom": "@hot-loader/react-dom"
    }
  },
  "devDependencies": {
    "@babel/core": "^7.8.4",
    "@babel/plugin-transform-runtime": "^7.8.3",
    "@babel/preset-env": "^7.8.4",
    "@babel/preset-react": "^7.8.3",
    "babel-eslint": "^10.0.3",
    "babel-loader": "^8.0.6",
    "cross-env": "^7.0.0",
    "css-loader": "^3.4.2",
    "eslint": "^6.1.0",
    "eslint-config-airbnb": "^18.0.1",
    "eslint-loader": "^3.0.3",
    "eslint-plugin-import": "^2.20.0",
    "eslint-plugin-jsx-a11y": "^6.2.3",
    "eslint-plugin-react": "^7.18.0",
    "eslint-plugin-react-hooks": "^1.7.0",
    "html-webpack-plugin": "^3.2.0",
    "node-sass": "^4.13.1",
    "sass-loader": "^8.0.2",
    "style-loader": "^1.1.3",
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.2"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "^1.2.27",
    "@fortawesome/free-solid-svg-icons": "^5.12.1",
    "@fortawesome/react-fontawesome": "^0.1.8",
    "@hot-loader/react-dom": "^16.11.0",
    "@types/react": "^16.9.19",
    "axios": "^0.19.2",
    "react": "^16.12.0",
    "react-beautiful-dnd": "^12.2.0",
    "react-dom": "^16.12.0",
    "react-hot-loader": "^4.12.19",
    "react-redux": "^7.1.3",
    "redux": "^4.0.5",
    "redux-saga": "^1.1.3"
  }
}

And webpack.config.js:

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const { env } = process;

module.exports = {
  entry: './src/index.js',
  mode: env.NODE_ENV,
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader', 'eslint-loader'],
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          // Creates `style` nodes from JS strings
          'style-loader',
          // Translates CSS into CommonJS
          'css-loader',
          // Compiles Sass to CSS
          'sass-loader',
        ],
      },
    ],
  },
  resolve: {
    extensions: ['*', '.js', '.jsx'],
  },
  output: {
    path: path.join(__dirname, '/build'),
    publicPath: '/',
    filename: 'bundle.js',
  },
  plugins: [
    new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(env.NODE_ENV) }),
    new HtmlWebpackPlugin({
      template: path.resolve('./src/index.html'),
    }),
  ],
  devServer: {
    contentBase: './build',
    hot: true,
  },
  devtool: env.NODE_ENV === 'development' ? 'cheap-module-eval-source-map' : undefined,
};

Also index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './redux/store';
import App from './components/App';
import './scss/main.scss';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('app'),
);

module.hot.accept();

Answers

Finally I've solve the issue by using nginx and running the build version in the container getting help from this great article.

The new Dockerfile and docker-compose.yml follows:

Dockerfile:

FROM node:12.14.1 as build
WORKDIR /app
COPY . /app
ENV PATH /app/node_modules/.bin:$PATH
RUN npm install
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

docker-compose.yml:

version: "3"
services:
  explore_dashboard:
    container_name: explore_dashboard
    build:
      context: .
      dockerfile:
        Dockerfile
    ports:
      - "8081:80"

nginx.conf:

server {
    listen 80;
    location / {
      root   /usr/share/nginx/html;
      index  index.html index.htm;
      try_files $uri $uri/ /index.html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
      root   /usr/share/nginx/html;
    }
  }

Now I'm able to run the app on http://127.0.0.1:8081/ running:

docker-compose up
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐