From 6c5bd1decdb15417920af6ae44ca14bd210b8b39 Mon Sep 17 00:00:00 2001 From: neverland Date: Mon, 9 Mar 2026 21:06:30 +0800 Subject: [PATCH] feat: migrate from connect to connect-next --- docs/migrate-v1-to-v2.md | 6 +-- package.json | 3 +- pnpm-lock.yaml | 58 ++++-------------------- rslib.config.ts | 1 - src/server.ts | 7 ++- src/types.ts | 2 +- tests/e2e/__snapshots__/app.test.js.snap | 32 ++++++------- tests/e2e/app.test.js | 11 +++-- 8 files changed, 42 insertions(+), 78 deletions(-) diff --git a/docs/migrate-v1-to-v2.md b/docs/migrate-v1-to-v2.md index 9089e13..dc67623 100644 --- a/docs/migrate-v1-to-v2.md +++ b/docs/migrate-v1-to-v2.md @@ -57,12 +57,12 @@ The minimum supported Node.js version is now `^20.19.0 || >=22.12.0`. > 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` +### Default app now uses `connect-next` When `devServer.app` is omitted, `@rspack/dev-server` now creates a -`connect` app instead of an Express app. +`connect-next` app instead of an Express app. -The dev server only needs a minimal middleware pipeline. Connect provides the same `(req, res, next)` interface as Express while being significantly smaller and having fewer dependencies, making it a better fit for this use case. +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: diff --git a/package.json b/package.json index 34c5f43..ea10bc5 100644 --- a/package.json +++ b/package.json @@ -45,13 +45,12 @@ ] }, "dependencies": { - "@types/connect": "^3.4.38", "@types/connect-history-api-fallback": "^1.5.4", "@types/serve-index": "^1.9.4", "@types/serve-static": "^2.2.0", "@types/ws": "^8.18.1", "chokidar": "^3.6.0", - "connect": "^3.7.0", + "connect-next": "^4.0.0", "connect-history-api-fallback": "^2.0.0", "http-proxy-middleware": "^3.0.5", "ipaddr.js": "^2.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e76b462..c6a361a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: dependencies: - '@types/connect': - specifier: ^3.4.38 - version: 3.4.38 '@types/connect-history-api-fallback': specifier: ^1.5.4 version: 1.5.4 @@ -26,12 +23,12 @@ importers: chokidar: specifier: ^3.6.0 version: 3.6.0 - connect: - specifier: ^3.7.0 - version: 3.7.0 connect-history-api-fallback: specifier: ^2.0.0 version: 2.0.0 + connect-next: + specifier: ^4.0.0 + version: 4.0.0 http-proxy-middleware: specifier: ^3.0.5 version: 3.0.5 @@ -1078,9 +1075,9 @@ packages: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} - connect@3.7.0: - resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} - engines: {node: '>= 0.10.0'} + connect-next@4.0.0: + resolution: {integrity: sha512-Kg/Ysjd0dsJ9Mw8oKCRfuCVc7BYSU6GSLNoOmwKd5S05bWsuIR/pjCZf/RaE5RiuRChGqW3nP2Z5YdwHhDfbKw==} + engines: {node: ^20.19.0 || >=22.12.0} content-disposition@1.0.1: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} @@ -1197,10 +1194,6 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -1321,10 +1314,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.1.2: - resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} - engines: {node: '>= 0.8'} - finalhandler@2.1.1: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} @@ -1663,10 +1652,6 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} - on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} - on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -2106,10 +2091,6 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -3171,12 +3152,11 @@ snapshots: connect-history-api-fallback@2.0.0: {} - connect@3.7.0: + connect-next@4.0.0: dependencies: - debug: 2.6.9 - finalhandler: 1.1.2 + debug: 4.4.3 + finalhandler: 2.1.1 parseurl: 1.3.3 - utils-merge: 1.0.1 transitivePeerDependencies: - supports-color @@ -3269,8 +3249,6 @@ snapshots: emoji-regex@8.0.0: {} - encodeurl@1.0.2: {} - encodeurl@2.0.0: {} end-of-stream@1.4.4: @@ -3404,18 +3382,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.1.2: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.3.0 - parseurl: 1.3.3 - statuses: 1.5.0 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - finalhandler@2.1.1: dependencies: debug: 4.4.3 @@ -3725,10 +3691,6 @@ snapshots: object-inspect@1.13.4: {} - on-finished@2.3.0: - dependencies: - ee-first: 1.1.1 - on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -4209,8 +4171,6 @@ snapshots: util-deprecate@1.0.2: {} - utils-merge@1.0.1: {} - vary@1.1.2: {} watchpack@2.5.1: diff --git a/rslib.config.ts b/rslib.config.ts index ea7787f..b730baf 100644 --- a/rslib.config.ts +++ b/rslib.config.ts @@ -8,7 +8,6 @@ export default defineConfig({ dts: true, output: { externals: { - connect: 'commonjs connect', 'connect-history-api-fallback': 'commonjs connect-history-api-fallback', 'webpack-dev-middleware': 'commonjs webpack-dev-middleware', diff --git a/src/server.ts b/src/server.ts index 871f345..060e4ae 100644 --- a/src/server.ts +++ b/src/server.ts @@ -142,7 +142,10 @@ const memoize = (fn: FunctionReturning): FunctionReturning => { }; }; -const getConnect = memoize(() => require('connect')); +const getConnect = async () => { + const { connect } = await import('connect-next'); + return connect; +}; const getServeStatic = memoize(() => require('serve-static')); const encodeOverlaySettings = ( @@ -1520,7 +1523,7 @@ class Server< this.app = ( typeof this.options.app === 'function' ? await this.options.app() - : getConnect()() + : (await getConnect())() ) as A; } diff --git a/src/types.ts b/src/types.ts index fa0bb03..841dc63 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,7 +21,7 @@ export type { FSWatcher, WatchOptions }; import type { Server as ConnectApplication, IncomingMessage as ConnectIncomingMessage, -} from 'connect'; +} from 'connect-next'; export type { ConnectApplication }; import type { Options as ConnectHistoryApiFallbackOptions } from 'connect-history-api-fallback'; export type { ConnectHistoryApiFallbackOptions }; diff --git a/tests/e2e/__snapshots__/app.test.js.snap b/tests/e2e/__snapshots__/app.test.js.snap index 8edb3d2..8cb458d 100644 --- a/tests/e2e/__snapshots__/app.test.js.snap +++ b/tests/e2e/__snapshots__/app.test.js.snap @@ -1,6 +1,6 @@ // Rstest Snapshot v1 -exports[`app option > should work using "connect (async)" application and "http" server > should handle GET request to index route (/) > console messages 1`] = ` +exports[`app option > should work using "connect-next (async)" application and "http" server > should handle GET request to index route (/) > console messages 1`] = ` [ "[rspack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", "[HMR] Waiting for update signal from WDS...", @@ -8,11 +8,11 @@ exports[`app option > should work using "connect (async)" application and "http" ] `; -exports[`app option > should work using "connect (async)" application and "http" server > should handle GET request to index route (/) > page errors 1`] = `[]`; +exports[`app option > should work using "connect-next (async)" application and "http" server > should handle GET request to index route (/) > page errors 1`] = `[]`; -exports[`app option > should work using "connect (async)" application and "http" server > should handle GET request to index route (/) > response status 1`] = `200`; +exports[`app option > should work using "connect-next (async)" application and "http" server > should handle GET request to index route (/) > response status 1`] = `200`; -exports[`app option > should work using "connect (async)" application and "http" server > should handle GET request to index route (/) > response text 1`] = ` +exports[`app option > should work using "connect-next (async)" application and "http" server > should handle GET request to index route (/) > response text 1`] = ` " @@ -28,7 +28,7 @@ exports[`app option > should work using "connect (async)" application and "http" " `; -exports[`app option > should work using "connect" application and "http" server > should handle GET request to index route (/) > console messages 1`] = ` +exports[`app option > should work using "connect-next" application and "http" server > should handle GET request to index route (/) > console messages 1`] = ` [ "[rspack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", "[HMR] Waiting for update signal from WDS...", @@ -36,11 +36,11 @@ exports[`app option > should work using "connect" application and "http" server ] `; -exports[`app option > should work using "connect" application and "http" server > should handle GET request to index route (/) > page errors 1`] = `[]`; +exports[`app option > should work using "connect-next" application and "http" server > should handle GET request to index route (/) > page errors 1`] = `[]`; -exports[`app option > should work using "connect" application and "http" server > should handle GET request to index route (/) > response status 1`] = `200`; +exports[`app option > should work using "connect-next" application and "http" server > should handle GET request to index route (/) > response status 1`] = `200`; -exports[`app option > should work using "connect" application and "http" server > should handle GET request to index route (/) > response text 1`] = ` +exports[`app option > should work using "connect-next" application and "http" server > should handle GET request to index route (/) > response text 1`] = ` " @@ -56,7 +56,7 @@ exports[`app option > should work using "connect" application and "http" server " `; -exports[`app option > should work using "connect" application and "http2" server > should handle GET request to index route (/) > console messages 1`] = ` +exports[`app option > should work using "connect-next" application and "http2" server > should handle GET request to index route (/) > console messages 1`] = ` [ "[rspack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", "[HMR] Waiting for update signal from WDS...", @@ -64,11 +64,11 @@ exports[`app option > should work using "connect" application and "http2" server ] `; -exports[`app option > should work using "connect" application and "http2" server > should handle GET request to index route (/) > page errors 1`] = `[]`; +exports[`app option > should work using "connect-next" application and "http2" server > should handle GET request to index route (/) > page errors 1`] = `[]`; -exports[`app option > should work using "connect" application and "http2" server > should handle GET request to index route (/) > response status 1`] = `200`; +exports[`app option > should work using "connect-next" application and "http2" server > should handle GET request to index route (/) > response status 1`] = `200`; -exports[`app option > should work using "connect" application and "http2" server > should handle GET request to index route (/) > response text 1`] = ` +exports[`app option > should work using "connect-next" application and "http2" server > should handle GET request to index route (/) > response text 1`] = ` " @@ -84,7 +84,7 @@ exports[`app option > should work using "connect" application and "http2" server " `; -exports[`app option > should work using "connect" application and "https" server > should handle GET request to index route (/) > console messages 1`] = ` +exports[`app option > should work using "connect-next" application and "https" server > should handle GET request to index route (/) > console messages 1`] = ` [ "[rspack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.", "[HMR] Waiting for update signal from WDS...", @@ -92,11 +92,11 @@ exports[`app option > should work using "connect" application and "https" server ] `; -exports[`app option > should work using "connect" application and "https" server > should handle GET request to index route (/) > page errors 1`] = `[]`; +exports[`app option > should work using "connect-next" application and "https" server > should handle GET request to index route (/) > page errors 1`] = `[]`; -exports[`app option > should work using "connect" application and "https" server > should handle GET request to index route (/) > response status 1`] = `200`; +exports[`app option > should work using "connect-next" application and "https" server > should handle GET request to index route (/) > response status 1`] = `200`; -exports[`app option > should work using "connect" application and "https" server > should handle GET request to index route (/) > response text 1`] = ` +exports[`app option > should work using "connect-next" application and "https" server > should handle GET request to index route (/) > response text 1`] = ` " diff --git a/tests/e2e/app.test.js b/tests/e2e/app.test.js index 282e430..6cc98af 100644 --- a/tests/e2e/app.test.js +++ b/tests/e2e/app.test.js @@ -12,13 +12,16 @@ const staticDirectory = path.resolve( '../fixtures/static-config/public', ); +const createConnectNextApp = () => + import('connect-next').then(({ connect }) => connect()); + const apps = [ ['express', () => require('express')(), 'http'], ['express', () => require('express')(), 'https'], - ['connect', () => require('connect')(), 'http'], - ['connect', () => require('connect')(), 'https'], - ['connect', () => require('connect')(), 'http2'], - ['connect (async)', () => require('connect')(), 'http'], + ['connect-next', createConnectNextApp, 'http'], + ['connect-next', createConnectNextApp, 'https'], + ['connect-next', createConnectNextApp, 'http2'], + ['connect-next (async)', async () => createConnectNextApp(), 'http'], [ 'hono', () => new (require('hono').Hono)(),