2

My Docker+NestJS+Webpack development environment is not running as efficiently as I would like.

Current behavior

Using Webpack with Hot Module Replacement Plugin is slower than using Nest-CLI with watch: nest build --webpack --webpackPath webpack-hmr.config.js --watch is slower than nest start --debug --watch.

It keeps rebuilding my source files; I'm assuming it keeps rebuilding the entire source, instead of hot module replacing; with a new project with a couple of files, it is much faster, and only replaces what is needed.

Input Code

Dockerfile:

# Get current Node Alpine Linux image.
FROM node:erbium-alpine AS base
# Install essential packages to prepare for bcrypt.
# https://github.com/kelektiv/node.bcrypt.js/wiki/Installation-Instructions#alpine-linux-based-images
RUN apk --no-cache add --virtual builds-deps builds-deps build-base gcc wget python
# Install is-docker to make sure the installations are only done within the container.
RUN yarn global add is-docker
# Set our node environment, either development or production;
# defaults to production, docker-compose overrides this to development on build and run.
ARG NODE_ENV=production
ENV NODE_ENV $NODE_ENV
# Expose port 3000 for node as default, unless otherwise stated.
ARG PORT=3000
ENV PORT $PORT
EXPOSE $PORT
# Install dependencies first, in a different location for easier app bind mounting for local development;
# we need to keep node_modules and its affiliated packages in 
# due to default /opt permissions we have to create the dir with root and change perms
WORKDIR /home/node/
# Copy files to prepare for installation.
COPY --chown=node:node package.json yarn.lock tsconfig.json tsconfig.build.json nest-cli.json ./

FROM base AS debug
# Expose port 9229 for debugging.
EXPOSE 9229
# Install git for husky hooks.
RUN apk --no-cache add git
# The official node image provides an unprivileged user as a security best practice
# but we have to manually enable it. We put it here so npm installs dependencies as the same
# user who runs the app.
# https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user
USER node
# Continue copy files to prepare for installation.
COPY --chown=node:node ./webpack/webpack-hmr-debug.config.js .run-if-changedrc ./
ADD --chown=node:node .husky .husky/
ADD --chown=node:node .git .git/
# Install dependencies.
RUN yarn
# Copy source files last.
ADD --chown=node:node src src/
# Start debugging!
CMD [ "yarn", "debug" ]

docker-compose.yml:

version : "3.7"
services:
  backend_debug:
    build:
      context: ..
      target: debug
      dockerfile: ./docker/Dockerfile
      args:
        - NODE_ENV=development
    profiles:
      - debug
    stop_signal   : SIGINT
    container_name: project_backend_debug
    restart       : unless-stopped
    ports         :
      - "3000:3000"
      - "9229:9229"
    environment: 
      - MONGO_URI
    stdin_open    : true # Keep stdin open regardless.
    tty           : true # Show output with syntax highlighting support.
    command: ['ash']
    volumes       :
      - "../webpack/webpack-hmr-debug.config.js:/home/node/webpack-hmr-debug.config.js"
      - "../tsconfig.build.json:/home/node/tsconfig.build.json"
      - "../.run-if-changedrc:/home/node/.run-if-changedrc"
      - "../nest-cli.json:/home/node/nest-cli.json"
      - "../tsconfig.json:/home/node/tsconfig.json"
      - "../node_modules:/home/node/node_modules/"
      - "../package.json:/home/node/package.json"
      - "../yarn.lock:/home/node/yarn.lock"
      - "../.husky/:/home/node/.husky/"
      - "../.git/:/home/node/.git/"
      - "../dist:/home/node/dist/"
      - "../src/:/home/node/src/"

webpack-hmr.config.js

const
  { RunScriptWebpackPlugin } = require('run-script-webpack-plugin'),
  nodeExternals              = require('webpack-node-externals');

module.exports = function (options, webpack) {
    return {
        ...options,
        entry: ['webpack/hot/poll?100', options.entry],
        devtool: 'inline-source-map',
        externals: [
            nodeExternals({
                allowlist: ['webpack/hot/poll?100'],
            }),
        ],
        plugins: [
            ...options.plugins,
            new webpack.HotModuleReplacementPlugin(),
            new webpack.WatchIgnorePlugin({
                paths: [/\.js$/, /\.d\.ts$/],
            }),
            new RunScriptWebpackPlugin(
                {
                    name: options.output.filename,
                    nodeArgs: ['--inspect=0.0.0.0:9229'] // Added to enable debugging.
                }
            ),
        ]
    };
};

Expected behavior

HMR should speed up development and show that HMR rebuilds by changing the specific files only.

Environment

Docker-Compose: 1.29.2 Webpack: 5.28.0 Docker: 20.10.8 Nest: 7.5.5

For Tooling issues:

  • Node: 12.22.6
  • Platform: MacOS Big Sur 11.5.2
yaserso
  • 2,638
  • 5
  • 41
  • 73

0 Answers0