WarpBuild LogoWarpBuild Docs

Node.js with Webpack

Best practices for Dockerfile for Node.js with Webpack

🐳 Annotated Dockerfile for Node.js with Webpack:

# Use Node.js LTS as the base image for consistency and long-term support
FROM node:lts-slim AS base
 
# Stage 1: Install dependencies
FROM base AS deps
 
# Set working directory
WORKDIR /app
 
# Copy only package definition files first
COPY package.json package-lock.json* ./
 
# Install dependencies
RUN --mount=type=cache,target=/root/.npm \
    npm ci
 
# Stage 2: Build the application
FROM base AS build
 
WORKDIR /app
 
# Copy dependencies
COPY --from=deps /app/node_modules ./node_modules
 
# Copy source code
COPY . .
 
# Build the application with Webpack
RUN --mount=type=cache,target=/root/.npm \
    npm run build
 
# Stage 3: Production image (using NGINX to serve static files)
FROM nginx:alpine
 
# Copy build output to NGINX serve directory
COPY --from=build /app/dist /usr/share/nginx/html
 
# Copy custom NGINX config if needed
# COPY nginx.conf /etc/nginx/conf.d/default.conf
 
# Add non-root user
RUN addgroup -g 1001 -S appuser && \
    adduser -u 1001 -S appuser -G appuser
 
# Set permissions
RUN chown -R appuser:appuser /usr/share/nginx/html && \
    chmod -R 755 /usr/share/nginx/html && \
    chown -R appuser:appuser /var/cache/nginx && \
    chown -R appuser:appuser /var/log/nginx && \
    chown -R appuser:appuser /etc/nginx/conf.d
 
# Set user
USER appuser
 
# Expose port
EXPOSE 80
 
# NGINX will start automatically
CMD ["nginx", "-g", "daemon off;"]

🔍 Why these are best practices for Webpack:

✅ Optimized build process

  • The multi-stage build approach keeps the final image size small
  • Webpack bundling creates optimized assets for production

✅ Dependency separation

  • Dependencies are installed in a separate stage, improving build caching
  • Production dependencies only are used in the final image

✅ Security enhancements

  • Running NGINX as a non-root user reduces security risks
  • Minimal attack surface with only the build artifacts in the final image

✅ Performance tuning

  • NGINX serves static files efficiently compared to Node.js servers
  • Proper file ownership and permissions for the web server

🚀 Additional Webpack-specific configurations:

Webpack Configuration Optimization

For production builds, ensure your webpack.config.js includes:

const path = require("path");
const TerserPlugin = require("terser-webpack-plugin");
 
module.exports = {
  mode: "production",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].[contenthash].js",
    clean: true,
  },
  optimization: {
    minimizer: [new TerserPlugin()],
    splitChunks: {
      chunks: "all",
    },
  },
};

Environment Variables in Webpack

Use the DefinePlugin to inject environment variables:

const webpack = require("webpack");
 
module.exports = {
  // ...other config
  plugins: [
    new webpack.DefinePlugin({
      "process.env.API_URL": JSON.stringify(process.env.API_URL),
    }),
  ],
};

And in the Dockerfile:

# In the build stage
ARG API_URL
ENV API_URL=${API_URL}

Custom NGINX Configuration for SPAs

server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;
 
    # SPA routing - redirect all requests to index.html
    location / {
        try_files $uri $uri/ /index.html;
    }
 
    # Cache static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
}

Development Setup with Docker Compose

version: "3"
services:
  webpack:
    build:
      context: .
      target: deps
    command: npm run start
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "8080:8080"
    environment:
      - API_URL=http://localhost:3000/api

By following these best practices, your Webpack applications will have optimized production builds with minimal container size and maximum security.

Last updated on

On this page