Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my webpack bundle successfully built on host machine but is not in docker container?

I have a monorepo structure of my project like this:

babel.config.js
  a-something
  b-something

where I have the babel config file in the root of my project and the packages a-something and b-something. Inside package a-something I have the following webpack config:

const path = require('path')

module.exports = {
  target: 'node',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'build')
  },
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.js?$/,
        use: {
          loader: 'babel-loader',
          options: {
            rootMode: 'upward'
          }
        },
        include: [
          path.resolve(__dirname, 'src'),
          /node_modules\/a-/,
          /node_modules\/b-/
        ]
      }
    ]
  }
}

Inside the package a-something I have the following package.json:

{
  "name": "a-something",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "prod:build": "webpack --config webpack.config.js",
    "prod:start": "node build/bundle.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.2",
    "graphql": "^14.5.8",
    "graphql-request": "^1.8.2",
    "graphql-tag": "^2.10.1",
    "b-something": "^1.0.0",
    "node-fetch": "^2.6.0",
    "sitemap": "^5.0.0"
  },
  "devDependencies": {
    "webpack": "3.5.6",
    "@babel/polyfill": "7.7.0"
  }
}

My root package.json has the following dependencies:

"@babel/cli": "^7.5.5",
"@babel/core": "^7.5.5",
"babel-loader": "8.0.6"

and lastly my Dockerfile inside package a-something is:

FROM node:10.15.1
COPY ./package.json /src/package.json
ENV PORT 3000
ENV NODE_ENV production
WORKDIR /src
RUN npm install
COPY ./lerna.json /src/lerna.json
COPY ./packages/a-something/package.json /src/packages/a-something/package.json
COPY ./packages/b-something/package.json /src/packages/b-something/package.json
RUN npm run clean
COPY . /src
WORKDIR /src/packages/a-something
RUN npm run prod:build
RUN echo "FINISHED BUILDING!" 
EXPOSE ${PORT}
CMD ["npm" , "run", "prod:start"]

When I run npm run prod: build and npm run prod: start the bundle is built successfully, however when I build the docker (where the context is the root folder) I get the following npm error:

ERROR in Entry module not found: Error: Can't resolve 'babel-loader' in '/src/packages/a-something'
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! [email protected] prod:build: `webpack --config webpack.config.js`
npm ERR! Exit status 2
npm ERR! 
npm ERR! Failed at the [email protected] prod:build script.

My host machine OS is macOS Mojave. Maybe the symlinks generated by Lerna are handled differently on Debian (used by node image)?


UPDATE: the issue was resolved by moving all babel related npm packages from devDependencies to dependencies section of root package.json. Does anyone have an idea why this would solve the problem?

like image 501
Yos Avatar asked Oct 16 '22 08:10

Yos


1 Answers

As I mentioned in the update section of my question the solution was to move all babel related packages to devDependencies section of the root package.json.

But why did this help?

The problem was I set NODE_ENV to production in Dockerfile. npm will not install dev dependencies if NODE_ENV is set to production. On the host machine I didn't have such variable. In addition another issue would've been @babel/polyfill, according to babel docs:

Because this is a polyfill (which will run before your source code), we need it to be a dependency, not a devDependency

According to the docs @babel/polyfill is also deprecated so the better solution is to:

  1. add "babel-loader": "8.0.6" to root package.json
  2. Have the following devDependencies in a-something package.json:
    "devDependencies": {
        "webpack": "3.5.6",
        "core-js": "^3.4.7",
        "regenerator-runtime": "^0.13.3"
      }
  1. Place these 2 lines in the entry Javascript file at the very top:
import 'core-js/stable'
import 'regenerator-runtime/runtime'
  1. Finally use this webpack config:
    const path = require('path')

    module.exports = {
      target: 'node',
      entry: './src/index.js',
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'build')
      },
      module: {
        rules: [
          {
            test: /\.js?$/,
            use: {
              loader: 'babel-loader',
              options: {
                rootMode: 'upward',
                presets: [
                  ['@babel/preset-env', {
                    corejs: 3,
                    useBuiltIns: 'usage'
                  }]
                ]
              }
            },
            include: [
              path.resolve(__dirname, 'src'),
                /node_modules\/a-/,
                /node_modules\/b-/
            ]
          }
        ]
      }
    }
like image 146
Yos Avatar answered Nov 12 '22 19:11

Yos