3

Information

I have an application (reactjs) that run with docker, It use webpack but at start it crash saying that html-loader can't be resolve. I install it but when I rerun docker, It continue to say that.

Error message

Html Webpack Plugin:
  Error: Child compilation failed:
  Entry module not found: Error: Can't resolve 'html-loader' in '/usr/src/app/client':
  Error: Can't resolve 'html-loader' in '/usr/src/app/client'

  - compiler.js:153 childCompiler.runAsChild
    [client]/[html-webpack-plugin]/lib/compiler.js:153:18

  - Compiler.js:306 compile
    [client]/[webpack]/lib/Compiler.js:306:11

  - Compiler.js:631 hooks.afterCompile.callAsync.err
    [client]/[webpack]/lib/Compiler.js:631:15


  - Hook.js:154 AsyncSeriesHook.lazyCompileHook
    [client]/[tapable]/lib/Hook.js:154:20

  - Compiler.js:628 compilation.seal.err
    [client]/[webpack]/lib/Compiler.js:628:31


  - Hook.js:154 AsyncSeriesHook.lazyCompileHook
    [client]/[tapable]/lib/Hook.js:154:20

  - Compilation.js:1329 hooks.optimizeAssets.callAsync.err
    [client]/[webpack]/lib/Compilation.js:1329:35

package.json

{
  "name": "client",
  "version": "1.1.0",
  "private": true,
  "dependencies": {
    "@babel/plugin-proposal-class-properties": "^7.4.0",
    "@babel/plugin-transform-runtime": "^7.2.0",
    "autosuggest-highlight": "^3.1.1",
    "axios": "^0.18.0",
    "babel-loader": "^8.0.5",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "body-parser": "^1.18.3",
    "css-loader": "^2.1.0",
    "d3": "^5.5.0",
    "email-validator": "^2.0.4",
    "file-loader": "^3.0.1",
    "history": "^4.7.2",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "js-file-download": "^0.4.4",
    "path": "^0.12.7",
    "react": "^16.4.1",
    "react-autosuggest": "^9.4.0",
    "react-cookie": "^3.0.4",
    "react-dnd": "^5.0.0",
    "react-dnd-html5-backend": "^5.0.1",
    "react-dom": "^16.4.1",
    "react-dropdown": "^1.6.2",
    "react-phone-number-input": "^2.2.15",
    "react-router-dom": "^4.3.1",
    "react-scripts": "^3.0.0",
    "reactstrap": "^6.3.1",
    "save-svg-as-png": "^1.4.7",
    "style-loader": "^0.23.1",
    "text-loader": "0.0.1",
    "topojson-client": "^3.0.0",
    "webpack": "^4.29.5",
    "webpack-cli": "^3.2.3"
  },
  "babel": {
    "presets": [
      "@babel/preset-env",
      "@babel/preset-react"
    ],
    "plugins": [
      "@babel/plugin-transform-runtime",
      "@babel/plugin-proposal-class-properties"
    ]
  },
  "scripts": {
    "start": "npm run client",
    "client": "webpack-dev-server --config ./webpack.config.js --mode development --host 0.0.0.0",
    "build": "webpack --mode production",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "devDependencies": {
    "webpack-dev-server": "^3.2.1"
  }
}

webpack.config.js

const HtmlWebPackPlugin = require("html-webpack-plugin");
const webpack = require("webpack");

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.(png|jpg)$/,
        use: {
          loader: 'file-loader',
          options: {
            name: '[name].[ext]'
          }
        }
      },
        {
        // Transform our own .css files with PostCSS and CSS-modules
        test: /\.css$/,
        exclude: /node_modules/,
        use: ['style-loader', 'css-loader'],
      }, {
        // Do not transform vendor's CSS with CSS-modules
        // The point is that they remain in global scope.
        // Since we require these CSS files in our JS or CSS files,
        // they will be a part of our compilation either way.
        // So, no need for ExtractTextPlugin here.
        test: /\.css$/,
        include: /node_modules/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.html$/,
        use: ["html-loader"]
      }
    ]
  },
  plugins: [
    new HtmlWebPackPlugin({
      template: "./public/index.html",
      filename: "./index.html"
    }),
    new webpack.DefinePlugin({
      'process.env': {
        SERVER_URL: JSON.stringify(process.env.SERVER_URL)
      },
    })
  ],
  externals: ["fs"],
  "output": {
    filename: '[name].[hash].js'
  }
};

Docker

I have in my application the server and client part, for the need, I remove the server part, so we have the Dockerfile for client in services/client/ and the docker-compose file in main project.

Dockerfile - client

# base image
FROM node:11.6.0-alpine

# set working directory
WORKDIR /usr/src/app/client

# add `/usr/src/app/node_modules/.bin` to $PATH
ENV PATH /usr/src/client/app/node_modules/.bin:$PATH

# install and cache app dependencies
COPY package.json /usr/src/app/client/package.json
RUN npm install --silent && \
npm install --silent webpack-dev-server

# start app
CMD ["npm", "start"]

docker-compose.yml - main project

version: '3.7'

services:

  client:
    container_name: client
    build:
      context: ./services/client
      dockerfile: Dockerfile
    volumes:
      - ./services/client:/usr/src/app/client
      - /usr/src/app/client/node_modules
    ports:
      - 8080:8080
    environment:
      - SERVER_URL=http://localhost:5001
    depends_on:
      - server

  nginx:
    container_name: nginx
    build:
      context: ./services/nginx
      dockerfile: Dockerfile
    restart: unless-stopped
    ports:
      - "80:80"
    depends_on:
      - client

I doesn't have found so many things, first I have think that I have forgot something, like a module but It doesn't seems to be that. I need help.

Update

Actually I'm trying to test in local but I'm facing an issue, perhaps it can help.

Error when start in local (npm start)

internal/modules/cjs/loader.js:596
    throw err;
    ^

Error: Cannot find module 'webpack-cli/bin/config-yargs'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:594:15)
    at Function.Module._load (internal/modules/cjs/loader.js:520:25)
    at Module.require (internal/modules/cjs/loader.js:650:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> ($path-to-project/services/client/node_modules/webpack-dev-server/bin/webpack-dev-server.js:77:1)
    at Module._compile (internal/modules/cjs/loader.js:702:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)
    at Module.load (internal/modules/cjs/loader.js:612:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
    at Function.Module._load (internal/modules/cjs/loader.js:543:3)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! client@1.1.0 client: `webpack-dev-server --config ./webpack.config.js --mode development --host 0.0.0.0`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the client@1.1.0 client script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/user/.npm/_logs/2019-04-24T14_05_19_879Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! client@1.1.0 start: `npm run client`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the client@1.1.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/user/.npm/_logs/2019-04-24T14_05_19_917Z-debug.log

Update 2

I success to start the application in local and seems to work. I have delete the node_modules/ folder and package-lock.json and I install first webpack and after all package.json.
Even if it work in local, on docker, it don't work.

Tryliom
  • 895
  • 1
  • 12
  • 37
  • 1
    What’s in the anonymous volume holding your `node_modules` folder? It will not get automatically repopulated if you change the contents of your image. – David Maze Apr 24 '19 at 13:39
  • @DavidMaze The folder `node_modules` have the content of the `node_modules` when the `npm install` is trigger, but I use this system on many project and it replace the content when we restart the docker, what I do. – Tryliom Apr 24 '19 at 13:48
  • this may help https://stackoverflow.com/questions/40379139/cannot-find-module-webpack-bin-config-yargs – Deep Apr 24 '19 at 14:14
  • @Deep I just try it and doesn't work. – Tryliom Apr 24 '19 at 14:16
  • @Deep After a total remove of webpack and reinstall the update work and I found a module uninstall (`html-webpack-plugin`) – Tryliom Apr 24 '19 at 14:20
  • @DavidMaze I'm sorry you're right, the `node_modules` isn't update when install or remove a module. That's the issue. – Tryliom Apr 24 '19 at 14:49

1 Answers1

2

Your volumes: declaration is causing this.

You make things work again if you get into this situation by running:

docker-compose stop client
docker-compose rm client
docker-compose up --build

...but note that this is exactly the set of commands you'd need to run if you didn't have the problematic volumes: declaration.

Your docker-compose.yml file tells Docker:

volumes:
  # This directory contains data that needs to be injected from
  # and/or persisted to the host.  Hide anything that's in the
  # image and use this host directory instead.
  - ./services/client:/usr/src/app/client

  # This directory also contains data that needs to be persisted
  # across container runs.  Hide anything that's in the volume or
  # the previous bind mount and use data in this volume instead.
  # ONLY THE FIRST TIME this container gets run, copy data from
  # the image into this volume.
  - /usr/src/app/client/node_modules

You should be able to create a routine Dockerfile and docker-compose.yml file to illustrate this. npm init a trivial program and run it. If you run, say, docker-compose run client sh, you will be able to see that the node_modules directory matches what's in the current build environment. If you then yarn add anything, though, even if you rebuild the image, the node_modules volume will not get updated: you've told Docker it contains persistent data, and it will only get populated if it's empty.

(The reverse corollary to this is that, if you do use docker-compose run to get a shell like this and hand-edit something in your node_modules directory, because you've asked for that directory to be persisted separately from the image, it will outlive the temporary container that this launches.)

The workflow that's generally worked for me is to use Node directly on the host for active development (and live reloading and good IDE support and ...), and to use Docker (building an image, not injecting code via volumes) for production deployments.

David Maze
  • 130,717
  • 29
  • 175
  • 215