webpack-dev-server: установка и базовая настройка

webpack-dev-server — инструмент для локальной разработки приложений на базе Webpack. Сервер запускает сборку проекта в памяти, автоматически отслеживает изменения файлов, обновляет браузер и предоставляет удобную среду для разработки без необходимости вручную пересобирать проект после каждого изменения.

Основные возможности:

  • автоматическая пересборка проекта;
  • live reload;
  • Hot Module Replacement (HMR);
  • обслуживание статических файлов;
  • проксирование API-запросов;
  • поддержка HTTPS;
  • настройка заголовков, маршрутов и middleware;
  • история маршрутизации для SPA;
  • интеграция с WebSocket.

В современных проектах webpack-dev-server практически всегда используется вместе с webpack и webpack-cli.


Установка webpack-dev-server

Установка выполняется как зависимость для разработки.

npm

npm install --save-dev webpack-dev-server

yarn

yarn add --dev webpack-dev-server

pnpm

pnpm add -D webpack-dev-server

Минимальная структура проекта

Пример структуры:

project/
├── src/
│   └── index.js
├── dist/
├── package.json
└── webpack.config.js

Базовая конфигурация Webpack

Минимальный конфигурационный файл:

const path = require('path');

module.exports = {
    mode: 'development',

    entry: './src/index.js',

    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
        clean: true
    }
};

Добавление devServer

Настройки сервера располагаются внутри свойства devServer.

const path = require('path');

module.exports = {
    mode: 'development',

    entry: './src/index.js',

    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
        clean: true
    },

    devServer: {
        port: 3000
    }
};

Скрипт запуска

В package.json обычно добавляют отдельный скрипт:

{
    "scripts": {
        "dev": "webpack serve"
    }
}

Запуск:

npm run dev

После запуска сервер становится доступен по адресу:

http://localhost:3000

Режим serve

Команда:

webpack serve

выполняет несколько действий одновременно:

  1. запускает Webpack;
  2. запускает dev server;
  3. включает отслеживание изменений;
  4. автоматически обновляет браузер.

Это отличается от команды:

webpack

которая просто создаёт сборку и завершает работу.


Настройка порта

Свойство port задаёт номер порта.

devServer: {
    port: 8080
}

Можно использовать строку:

devServer: {
    port: 'auto'
}

В этом случае Webpack автоматически выберет свободный порт.


Настройка host

По умолчанию сервер доступен только локально.

devServer: {
    host: 'localhost'
}

Для доступа из локальной сети:

devServer: {
    host: '0.0.0.0'
}

Это полезно при тестировании на телефонах, планшетах и других устройствах.


Автоматическое открытие браузера

Свойство open автоматически открывает браузер после запуска сервера.

devServer: {
    open: true
}

Можно указать конкретный браузер:

devServer: {
    open: {
        app: {
            name: 'chrome'
        }
    }
}

Статические файлы

Свойство static определяет директорию для обслуживания статических ресурсов.

devServer: {
    static: path.resolve(__dirname, 'public')
}

Структура:

project/
├── public/
│   ├── favicon.ico
│   └── robots.txt

Файлы становятся доступны напрямую:

http://localhost:3000/favicon.ico

Несколько статических директорий

Допускается массив:

devServer: {
    static: [
        path.resolve(__dirname, 'public'),
        path.resolve(__dirname, 'assets')
    ]
}

Watch для static

По умолчанию изменения статических файлов отслеживаются автоматически.

Явная настройка:

devServer: {
    static: {
        directory: path.resolve(__dirname, 'public'),
        watch: true
    }
}

Отключение наблюдения:

devServer: {
    static: {
        directory: path.resolve(__dirname, 'public'),
        watch: false
    }
}

Live Reload

Live Reload обновляет страницу после изменения файлов.

devServer: {
    liveReload: true
}

Механизм работы:

  1. Webpack фиксирует изменение;
  2. выполняется пересборка;
  3. браузер получает сигнал;
  4. страница перезагружается.

Hot Module Replacement (HMR)

HMR обновляет модули без полной перезагрузки страницы.

devServer: {
    hot: true
}

Преимущества:

  • сохранение состояния приложения;
  • быстрые обновления;
  • снижение времени разработки;
  • отсутствие полной перезагрузки DOM.

Отличие HMR от Live Reload

Live Reload

Полностью обновляет страницу.

Изменение → сборка → reload страницы

HMR

Обновляет только изменённый модуль.

Изменение → сборка → замена модуля

Пример HMR

index.js

import './style.css';

console.log('Application started');

webpack.config.js

devServer: {
    hot: true
}

История маршрутизации SPA

Для React Router, Vue Router и других SPA используется:

devServer: {
    historyApiFallback: true
}

Без этой настройки при обновлении страницы:

http://localhost:3000/profile

сервер попытается найти физический файл /profile и вернёт 404.

С включённым historyApiFallback сервер всегда отдаёт index.html.


Настройка HTTPS

Включение HTTPS:

devServer: {
    https: true
}

Современный вариант:

devServer: {
    server: 'https'
}

Использование собственных сертификатов

const fs = require('fs');

devServer: {
    server: {
        type: 'https',
        options: {
            key: fs.readFileSync('./certs/server.key'),
            cert: fs.readFileSync('./certs/server.crt')
        }
    }
}

Сжатие gzip

Свойство compress включает gzip-сжатие.

devServer: {
    compress: true
}

Это позволяет приблизить локальную среду к production-режиму.


Настройка client

Секция client управляет поведением браузерного клиента Webpack.

devServer: {
    client: {
        overlay: true
    }
}

Overlay ошибок

Ошибки компиляции могут отображаться поверх страницы.

devServer: {
    client: {
        overlay: {
            errors: true,
            warnings: false
        }
    }
}

Логи в браузере

devServer: {
    client: {
        logging: 'info'
    }
}

Возможные значения:

  • none
  • error
  • warn
  • info
  • log
  • verbose

Индикатор прогресса

devServer: {
    client: {
        progress: true
    }
}

Настройка WebSocket

devServer: {
    client: {
        webSocketURL: 'ws://0.0.0.0:8080/ws'
    }
}

Используется при сложных конфигурациях reverse proxy.


Proxy API-запросов

Одна из самых важных возможностей webpack-dev-server.

Пример:

devServer: {
    proxy: {
        '/api': {
            target: 'http://localhost:5000',
            changeOrigin: true
        }
    }
}

Запрос:

http://localhost:3000/api/users

будет проксирован на:

http://localhost:5000/api/users

Для чего нужен proxy

Основные причины:

  • обход CORS;
  • разделение frontend/backend;
  • локальная разработка;
  • имитация production-инфраструктуры.

Изменение пути запроса

devServer: {
    proxy: {
        '/api': {
            target: 'http://localhost:5000',
            pathRewrite: {
                '^/api': ''
            }
        }
    }
}

Теперь:

/api/users

станет:

/users

Несколько proxy

devServer: {
    proxy: {
        '/api': {
            target: 'http://localhost:5000'
        },

        '/auth': {
            target: 'http://localhost:7000'
        }
    }
}

Настройка headers

Добавление HTTP-заголовков:

devServer: {
    headers: {
        'X-Custom-Header': 'webpack'
    }
}

Разрешённые хосты

devServer: {
    allowedHosts: 'all'
}

Или:

devServer: {
    allowedHosts: [
        'localhost',
        '.example.com'
    ]
}

Настройка devMiddleware

devMiddleware управляет внутренним middleware Webpack.

devServer: {
    devMiddleware: {
        writeToDisk: true
    }
}

По умолчанию сборка хранится только в памяти.


Запись файлов на диск

Обычный режим работы:

Webpack → memory filesystem

С writeToDisk:

Webpack → memory filesystem + физические файлы

Это полезно:

  • для интеграции с backend;
  • при работе с CMS;
  • при использовании SSR;
  • для отладки артефактов сборки.

Настройка publicPath

devServer: {
    devMiddleware: {
        publicPath: '/build/'
    }
}

Настройка watchFiles

Дополнительное отслеживание файлов:

devServer: {
    watchFiles: [
        'src/**/*.html',
        'templates/**/*.twig'
    ]
}

Настройка bonjour

Автоматическое обнаружение сервера в локальной сети:

devServer: {
    bonjour: true
}

Настройка IPC

Использование Unix Socket:

devServer: {
    ipc: true
}

Настройка webSocketServer

devServer: {
    webSocketServer: 'ws'
}

Варианты:

  • ws
  • sockjs

Полный пример базовой конфигурации

const path = require('path');

module.exports = {
    mode: 'development',

    entry: './src/index.js',

    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
        clean: true
    },

    devtool: 'eval-source-map',

    devServer: {
        port: 3000,

        host: 'localhost',

        open: true,

        hot: true,

        compress: true,

        historyApiFallback: true,

        static: {
            directory: path.resolve(__dirname, 'public'),
            watch: true
        },

        client: {
            overlay: true,
            progress: true
        },

        proxy: {
            '/api': {
                target: 'http://localhost:5000',
                changeOrigin: true
            }
        }
    }
};

Типичная конфигурация для React SPA

devServer: {
    port: 3000,

    hot: true,

    open: true,

    historyApiFallback: true,

    static: {
        directory: path.resolve(__dirname, 'public')
    }
}

Типичная конфигурация для Vue

devServer: {
    hot: true,

    compress: true,

    historyApiFallback: true
}

Типичная конфигурация для backend-интеграции

devServer: {
    devMiddleware: {
        writeToDisk: true
    },

    static: false
}

Ошибка: command not found

Причина:

webpack: command not found

обычно связана с отсутствием webpack-cli.

Решение:

npm install --save-dev webpack-cli

Ошибка: Invalid configuration object

Причины:

  • опечатка в webpack.config.js;
  • несовместимая версия;
  • устаревшие параметры;
  • неправильная структура объекта.

Ошибка: Port already in use

Причина:

EADDRINUSE

Порт уже используется другим процессом.

Решения:

devServer: {
    port: 'auto'
}

или использование другого порта.


Ошибка: Cannot GET /route

Причина — отсутствие:

historyApiFallback: true

Ошибка HMR не работает

Частые причины:

  • отключён hot;
  • используется full reload;
  • модуль не поддерживает HMR;
  • ошибки в runtime;
  • конфликт с framework tooling.

Совместимость версий

Webpack 5 требует современные версии webpack-dev-server.

Типичная связка:

webpack: 5.x
webpack-cli: 5.x
webpack-dev-server: 4.x или 5.x

Отличие webpack-dev-server от webpack-dev-middleware

webpack-dev-server

Готовый сервер разработки.

Включает:

  • HTTP server;
  • WebSocket;
  • HMR;
  • live reload;
  • proxy;
  • static hosting.

webpack-dev-middleware

Только middleware.

Используется внутри собственных Express/Koa/Fastify серверов.


Когда webpack-dev-server не используется

Иногда проекты переходят на:

  • Vite;
  • Next.js;
  • Nuxt;
  • Parcel;
  • Turbopack;
  • собственные dev-серверы.

Однако webpack-dev-server по-прежнему широко применяется:

  • в enterprise-проектах;
  • в legacy-системах;
  • в сложных webpack-конфигурациях;
  • в крупных monorepo;
  • в CMS-интеграциях;
  • в Bitrix- и WordPress-проектах;
  • в микрофронтенд-архитектуре.