diff --git a/lib/Server.js b/lib/Server.js index a168fb1c4e..8c6451b43b 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -1272,53 +1272,6 @@ class Server { * } */ if (typeof options.proxy !== "undefined") { - // TODO remove in the next major release, only accept `Array` - if (!Array.isArray(options.proxy)) { - if ( - Object.prototype.hasOwnProperty.call(options.proxy, "target") || - Object.prototype.hasOwnProperty.call(options.proxy, "router") - ) { - /** @type {ProxyConfigArray} */ - (options.proxy) = [/** @type {ProxyConfigMap} */ (options.proxy)]; - } else { - /** @type {ProxyConfigArray} */ - (options.proxy) = Object.keys(options.proxy).map( - /** - * @param {string} context - * @returns {HttpProxyMiddlewareOptions} - */ - (context) => { - let proxyOptions; - // For backwards compatibility reasons. - const correctedContext = context - .replace(/^\*$/, "**") - .replace(/\/\*$/, ""); - - if ( - typeof ( - /** @type {ProxyConfigMap} */ (options.proxy)[context] - ) === "string" - ) { - proxyOptions = { - context: correctedContext, - target: - /** @type {ProxyConfigMap} */ - (options.proxy)[context], - }; - } else { - proxyOptions = { - // @ts-ignore - .../** @type {ProxyConfigMap} */ (options.proxy)[context], - }; - proxyOptions.context = correctedContext; - } - - return proxyOptions; - } - ); - } - } - /** @type {ProxyConfigArray} */ (options.proxy) = /** @type {ProxyConfigArray} */ diff --git a/lib/options.json b/lib/options.json index f463557476..400783783f 100644 --- a/lib/options.json +++ b/lib/options.json @@ -467,24 +467,17 @@ "link": "https://webpack.js.org/configuration/dev-server/#devserverport" }, "Proxy": { - "anyOf": [ - { - "type": "object" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "object" - }, - { - "instanceof": "Function" - } - ] + "type": "array", + "items": { + "anyOf": [ + { + "type": "object" + }, + { + "instanceof": "Function" } - } - ], + ] + }, "description": "Allows to proxy requests, can be useful when you have a separate API backend development server and you want to send API requests on the same domain.", "link": "https://webpack.js.org/configuration/dev-server/#devserverproxy" }, diff --git a/test/__snapshots__/validate-options.test.js.snap.webpack5 b/test/__snapshots__/validate-options.test.js.snap.webpack5 index d0359d6adb..dde6c25cb9 100644 --- a/test/__snapshots__/validate-options.test.js.snap.webpack5 +++ b/test/__snapshots__/validate-options.test.js.snap.webpack5 @@ -474,28 +474,26 @@ exports[`options validate should throw an error on the "port" option with 'null' exports[`options validate should throw an error on the "proxy" option with '() => {}' value 1`] = ` "ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema. - - options.proxy should be one of these: - object { … } | [object { … } | function, ...] + - options.proxy should be an array: + [object { … } | function, ...] -> Allows to proxy requests, can be useful when you have a separate API backend development server and you want to send API requests on the same domain. - -> Read more at https://webpack.js.org/configuration/dev-server/#devserverproxy - Details: - * options.proxy should be an object: - object { … } - * options.proxy should be an array: - [object { … } | function, ...]" + -> Read more at https://webpack.js.org/configuration/dev-server/#devserverproxy" +`; + +exports[`options validate should throw an error on the "proxy" option with '{"/api":"http://localhost:3000"}' value 1`] = ` +"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema. + - options.proxy should be an array: + [object { … } | function, ...] + -> Allows to proxy requests, can be useful when you have a separate API backend development server and you want to send API requests on the same domain. + -> Read more at https://webpack.js.org/configuration/dev-server/#devserverproxy" `; exports[`options validate should throw an error on the "proxy" option with 'false' value 1`] = ` "ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema. - - options.proxy should be one of these: - object { … } | [object { … } | function, ...] + - options.proxy should be an array: + [object { … } | function, ...] -> Allows to proxy requests, can be useful when you have a separate API backend development server and you want to send API requests on the same domain. - -> Read more at https://webpack.js.org/configuration/dev-server/#devserverproxy - Details: - * options.proxy should be an object: - object { … } - * options.proxy should be an array: - [object { … } | function, ...]" + -> Read more at https://webpack.js.org/configuration/dev-server/#devserverproxy" `; exports[`options validate should throw an error on the "server" option with '{"type":"https","additional":"test"}' value 1`] = ` diff --git a/test/server/proxy-option.test.js b/test/server/proxy-option.test.js index f5ffcf2857..947f2a3864 100644 --- a/test/server/proxy-option.test.js +++ b/test/server/proxy-option.test.js @@ -13,15 +13,18 @@ const [port1, port2, port3, port4] = require("../ports-map")["proxy-option"]; const WebSocketServer = WebSocket.Server; const staticDirectory = path.resolve(__dirname, "../fixtures/proxy-config"); -const proxyOptionPathsAsProperties = { - "/proxy1": { +const proxyOptionPathsAsProperties = [ + { + context: "/proxy1", target: `http://localhost:${port1}`, }, - "/api/proxy2": { + { + context: "/api/proxy2", target: `http://localhost:${port2}`, pathRewrite: { "^/api": "" }, }, - "/foo": { + { + context: "/foo", bypass(req) { if (/\.html$/.test(req.path)) { return "/index.html"; @@ -30,14 +33,16 @@ const proxyOptionPathsAsProperties = { return null; }, }, - "/proxyfalse": { + { + context: "proxyfalse", bypass(req) { if (/\/proxyfalse$/.test(req.path)) { return false; } }, }, - "/proxy/async": { + { + context: "/proxy/async", bypass(req, res) { if (/\/proxy\/async$/.test(req.path)) { return new Promise((resolve) => { @@ -49,7 +54,8 @@ const proxyOptionPathsAsProperties = { } }, }, - "/bypass-with-target": { + { + context: "/bypass-with-target", target: `http://localhost:${port1}`, changeOrigin: true, secure: false, @@ -59,15 +65,17 @@ const proxyOptionPathsAsProperties = { } }, }, -}; +]; -const proxyOption = { - context: () => true, - target: `http://localhost:${port1}`, -}; +const proxyOption = [ + { + context: () => true, + target: `http://localhost:${port1}`, + }, +]; const proxyOptionOfArray = [ - { context: "/proxy1", target: proxyOption.target }, + { context: "/proxy1", target: `http://localhost:${port1}` }, function proxy(req, res, next) { return { context: "/api/proxy2", @@ -90,20 +98,26 @@ const proxyOptionOfArrayWithoutTarget = [ }, ]; -const proxyWithPath = { - "/proxy1": { +const proxyWithPath = [ + { + context: "/proxy1", path: `http://localhost:${port1}`, target: `http://localhost:${port1}`, }, -}; +]; -const proxyWithString = { - "/proxy1": `http://localhost:${port1}`, -}; +const proxyWithString = [ + { + context: "/proxy1", + target: `http://localhost:${port1}`, + }, +]; -const proxyWithRouterAsObject = { - router: () => `http://localhost:${port1}`, -}; +const proxyWithRouterAsObject = [ + { + router: () => `http://localhost:${port1}`, + }, +]; describe("proxy option", () => { let proxyServer1; @@ -478,19 +492,21 @@ describe("proxy option", () => { let req; let listener; - const proxyTarget = { - target: `http://localhost:${port1}`, - }; - beforeAll(async () => { const compiler = webpack(config); server = new Server( { - proxy: { - "/proxy1": proxyTarget, - "/proxy2": proxyTarget, - }, + proxy: [ + { + context: "/proxy1", + target: `http://localhost:${port1}`, + }, + { + context: "/proxy2", + target: `http://localhost:${port1}`, + }, + ], port: port3, }, compiler @@ -605,18 +621,18 @@ describe("proxy option", () => { let server; let req; let listener; - const proxyTarget = { - target: `http://localhost:${port1}`, - }; beforeAll(async () => { const compiler = webpack(config); server = new Server( { - proxy: { - "**": proxyTarget, - }, + proxy: [ + { + context: "**", + target: `http://localhost:${port1}`, + }, + ], port: port3, }, compiler @@ -742,12 +758,12 @@ describe("proxy option", () => { server = new Server( { - proxy: { - "*": { + proxy: [ + { context: () => true, target: `http://localhost:${port1}`, }, - }, + ], port: port3, }, compiler @@ -791,13 +807,14 @@ describe("proxy option", () => { server = new Server( { - proxy: { - "/my-path": { + proxy: [ + { + context: "/my-path", target: "http://unknown:1234", logProvider: () => customLogProvider, logLevel: "error", }, - }, + ], port: port3, }, compiler @@ -842,13 +859,14 @@ describe("proxy option", () => { server = new Server( { - proxy: { - "/my-path": { + proxy: [ + { + context: "my-path", target: "http://unknown:1234", logProvider: () => customLogProvider, logLevel: "silent", }, - }, + ], port: port3, }, compiler @@ -896,12 +914,13 @@ describe("proxy option", () => { server = new Server( { - proxy: { - "/my-path": { + proxy: [ + { + context: "/my-path", target: "http://unknown:1234", logProvider: () => customLogProvider, }, - }, + ], port: port3, }, compiler @@ -949,12 +968,13 @@ describe("proxy option", () => { server = new Server( { - proxy: { - "/my-path": { + proxy: [ + { + context: "/my-path", target: "http://unknown:1234", logProvider: () => customLogProvider, }, - }, + ], port: port3, }, compiler diff --git a/test/validate-options.test.js b/test/validate-options.test.js index ca843c49d7..e9a7121c7f 100644 --- a/test/validate-options.test.js +++ b/test/validate-options.test.js @@ -239,11 +239,14 @@ const tests = { target: "http://localhost:3000", }, ], + ], + failure: [ + () => {}, + false, { "/api": "http://localhost:3000", }, ], - failure: [() => {}, false], }, server: { success: [ diff --git a/types/lib/Server.d.ts b/types/lib/Server.d.ts index 8ef1a038c9..7df37bad39 100644 --- a/types/lib/Server.d.ts +++ b/types/lib/Server.d.ts @@ -823,34 +823,25 @@ declare class Server { link: string; }; Proxy: { - anyOf: ( - | { - type: string; - items?: undefined; - } - | { - type: string; - items: { - anyOf: ( - | { - type: string; - instanceof?: undefined; - } - | { - instanceof: string; - type?: undefined; - } - )[]; - }; - } - )[]; + type: string; + items: { + anyOf: ( + | { + type: string; + instanceof?: undefined; + } + | { + instanceof: string; + type?: undefined; + } + )[]; + }; description: string; - link: string /** @type {ClientConfiguration} */; + link: string; }; - /** @type {ClientConfiguration} */ Server: { anyOf: { - $ref: string; + $ref: string /** @type {WebSocketURL} */; }[]; link: string; description: string; @@ -859,6 +850,7 @@ declare class Server { enum: string[]; }; ServerEnum: { + /** @type {string} */ enum: string[]; cli: { exclude: boolean; @@ -866,7 +858,7 @@ declare class Server { }; ServerString: { type: string; - /** @type {ServerConfiguration} */ minLength: number; + minLength: number; cli: { exclude: boolean; }; @@ -881,13 +873,14 @@ declare class Server { }; options: { $ref: string; - } /** @type {string} */; + }; }; additionalProperties: boolean; }; ServerOptions: { type: string; additionalProperties: boolean; + /** @type {string} */ properties: { passphrase: { type: string; @@ -1106,7 +1099,7 @@ declare class Server { } | { $ref: string; - /** @type {MultiCompiler} */ type?: undefined; + type?: undefined; items?: undefined; cli?: undefined /** @typedef {import("express").Request} Request */; } @@ -1121,7 +1114,7 @@ declare class Server { directory: { type: string; minLength: number; - /** @type {MultiCompiler} */ description: string; + description: string; link: string; }; staticOptions: { @@ -1162,6 +1155,10 @@ declare class Server { cli?: undefined /** @typedef {import("express").Request} Request */; } )[]; + /** + * @param {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} watchOptions + * @returns {WatchOptions} + */ description: string; link: string; };