# @rspack/dev-server Migration Guide (v1 -> v2) This guide covers breaking changes you need to handle when upgrading `@rspack/dev-server` from v1 to v2. ## Breaking Changes ### Drop Node 18 Support Node.js 18 is no longer supported in v2. The minimum supported Node.js version is now `^20.19.0 || >=22.12.0`. ### Drop Rspack v1 Support `@rspack/dev-server` v2 is designed to work with Rspack v2. Rspack v1 is no longer supported in v2. ### Pure ESM package `@rspack/dev-server` is now published as **pure ESM** package. ### Upgraded `http-proxy-middleware` to v4 `http-proxy-middleware` has been updated from v2 to v4, with several breaking changes introduced since v3: - `proxy[].path` is removed. Use `pathFilter` (or `context`) instead. ```diff { - path: '/api', + pathFilter: '/api', } ``` - `logLevel` / `logProvider` are replaced by `logger`. ```diff - logLevel: 'warn', + logger: console, ``` - `onProxyReq` / `onProxyRes` / `onProxyReqWs` are moved to `on: { ... }`. ```diff - onProxyReq(proxyReq) { - proxyReq.setHeader('x-from', 'dev-server'); - }, + on: { + proxyReq(proxyReq) { + proxyReq.setHeader('x-from', 'dev-server'); + }, + }, ``` - `proxy[].bypass` is removed, use `pathFilter` or `router` instead. - When `bypass` was used and that function returned a boolean, it would automatically result in a 404 request. This can’t be achieved in a similar way now, or, if it returned a string, you can do what was done in the example above. - `bypass` also allowed sending data; this can no longer be done. If you really need to do it, you’d have to create a new route in the proxy that sends the same data, or alternatively create a new route on the main server and, following the example above, send the data you wanted. > Refer to the [http-proxy-middleware v3 migration guide](https://github.com/chimurai/http-proxy-middleware/blob/master/MIGRATION.md) for details. ### Default app now uses `connect-next` When `devServer.app` is omitted, `@rspack/dev-server` now creates a `connect-next` app instead of an Express app. The dev server only needs a minimal middleware pipeline. [connect-next](https://github.com/rstackjs/connect-next) is an actively maintained fork of Connect that keeps the same `(req, res, next)` middleware interface while staying smaller than Express and having fewer dependencies. If you relied on Express-only APIs on `devServer.app`, such as `app.get()`, `app.post()`, or `res.send()`, provide your own Express app explicitly: ```js import express from 'express'; export default { devServer: { app: async () => express(), }, }; ``` ### Updated `chokidar` to v5 `@rspack/dev-server` v2 upgrades the underlying file watcher `chokidar` from v3 to v5. One important breaking change in `chokidar` v4+ is that [glob patterns are no longer supported](https://github.com/paulmillr/chokidar#upgrading). If you previously passed glob patterns such as `**/*.js` or `./directory/**/*` to `devServer.watchFiles`, you can watch a directory and filter with `ignored`: ```js // Before export default { devServer: { watchFiles: '**/*.js', }, }; // After export default { devServer: { watchFiles: { paths: '.', options: { ignored: (path, stats) => stats?.isFile() && !path.endsWith('.js'), }, }, }, }; ``` Or use `node:fs/promises` to expand the glob first: ```js import { glob } from 'node:fs/promises'; export default async () => ({ devServer: { watchFiles: await Array.fromAsync(glob('**/*.js')), }, }); ``` ### Removed `spdy` support - `server.type: "spdy"` is no longer supported. - `server.options.spdy` is no longer supported. You can switch to `server.type: "http2"` or `"https"` instead. ```js // Before export default { devServer: { server: { type: 'spdy', options: { spdy: { protocols: ['h2', 'http/1.1'] }, }, }, }, }; // After export default { devServer: { server: { type: 'http2', // or 'https' options: {}, }, }, }; ``` > `Array.fromAsync()` requires Node.js 22+. ### Optional `selfsigned` peer dependency `selfsigned` is no longer bundled as a direct dependency of `@rspack/dev-server`. If you use `server.type: "https"` or `"http2"` without providing your own `server.options.key` and `server.options.cert`, the dev server needs `selfsigned` to generate a local certificate. Install it in your project when needed: ```bash npm i -D selfsigned@^5.0.0 # or pnpm add -D selfsigned@^5.0.0 # or yarn add -D selfsigned@^5.0.0 # or bun add -D selfsigned@^5.0.0 ``` ### Removed `serve-index` support `devServer.static.serveIndex` is removed in v2 to reduce third-party dependencies. If you still need directory listings for a static directory, install [serve-index](https://www.npmjs.com/package/serve-index) and register it with `setupMiddlewares`: ```bash npm i -D serve-index # or pnpm add -D serve-index # or yarn add -D serve-index # or bun add -D serve-index ``` ```js import path from 'node:path'; import serveIndex from 'serve-index'; const publicDirectory = path.join(import.meta.dirname, 'public'); export default { devServer: { static: { directory: publicDirectory, }, setupMiddlewares: (middlewares) => { middlewares.push({ name: 'serve-index', // The same as `static.publicPath` path: '/', middleware: serveIndex(publicDirectory, { icons: true }), }); return middlewares; }, }, }; ``` ### Removed SockJS support (`ws` only) In v2, the following SockJS options are no longer available: - `webSocketServer: "sockjs"` - `webSocketServer: { type: "sockjs" }` - `client.webSocketTransport: "sockjs"` - `webSocketServer.options.prefix` (use `path`) Also, SockJS bundle routes were removed. ```js // Before export default { devServer: { webSocketServer: 'sockjs', client: { webSocketTransport: 'sockjs', }, }, }; // After export default { devServer: { webSocketServer: 'ws', client: { webSocketTransport: 'ws', }, }, }; ``` If you need a non-default transport/server, you can provide a custom implementation path instead of `'sockjs'`. ### Removed `bonjour` Built-in Bonjour support is removed in v2. If Bonjour/ZeroConf broadcasting is still important for your workflow, consider integrating `bonjour-service` directly in your app code. ### Renamed `webpack-dev-server-*` to `rspack-dev-server-*` If your setup still uses the legacy names, you can update them as follows: - Environment variables - `WEBPACK_DEV_SERVER_BASE_PORT` -> `RSPACK_DEV_SERVER_BASE_PORT` - `WEBPACK_DEV_SERVER_PORT_RETRY` -> `RSPACK_DEV_SERVER_PORT_RETRY` - `WEBPACK_SERVE` -> `RSPACK_SERVE` - URL query flags - `webpack-dev-server-hot=false` -> `rspack-dev-server-hot=false` - `webpack-dev-server-live-reload=false` -> `rspack-dev-server-live-reload=false` - Built-in routes - `/webpack-dev-server/*` -> `/rspack-dev-server/*` ```txt # Before http://localhost:8080/?webpack-dev-server-hot=false&webpack-dev-server-live-reload=false GET /webpack-dev-server/invalidate GET /webpack-dev-server/open-editor?fileName=... # After http://localhost:8080/?rspack-dev-server-hot=false&rspack-dev-server-live-reload=false GET /rspack-dev-server/invalidate GET /rspack-dev-server/open-editor?fileName=... ```