diff --git a/lib/Server.js b/lib/Server.js index 0f73cd5509..480dd50e15 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -491,17 +491,27 @@ class Server { } // normalize `headers` - if ( - typeof options.headers !== "undefined" && - Array.isArray(options.headers) - ) { + if (typeof options.headers !== "undefined") { const allHeaders = {}; - options.headers.forEach((header) => { - allHeaders[header.key] = header.value; - }); + if (Array.isArray(options.headers)) { + options.headers.forEach((header) => { + allHeaders[header.key] = header.value; + }); + options.headers = allHeaders; + } - options.headers = allHeaders; + if (typeof options.headers === "function") { + const returnedHeaders = options.headers(); + + if (Array.isArray(returnedHeaders)) { + returnedHeaders.forEach((header) => { + allHeaders[header.key] = header.value; + }); + + options.headers = allHeaders; + } + } } if (typeof options.historyApiFallback === "undefined") { diff --git a/test/e2e/__snapshots__/headers.test.js.snap.webpack4 b/test/e2e/__snapshots__/headers.test.js.snap.webpack4 index c9edf9f641..2deab3832d 100644 --- a/test/e2e/__snapshots__/headers.test.js.snap.webpack4 +++ b/test/e2e/__snapshots__/headers.test.js.snap.webpack4 @@ -1,5 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`headers option as a function returning an array should handle GET request with headers: console messages 1`] = `Array []`; + +exports[`headers option as a function returning an array should handle GET request with headers: page errors 1`] = `Array []`; + +exports[`headers option as a function returning an array should handle GET request with headers: response headers x-bar 1`] = `"value2"`; + +exports[`headers option as a function returning an array should handle GET request with headers: response headers x-foo 1`] = `"value1"`; + +exports[`headers option as a function returning an array should handle GET request with headers: response status 1`] = `200`; + exports[`headers option as a function should handle GET request with headers as a function: console messages 1`] = `Array []`; exports[`headers option as a function should handle GET request with headers as a function: page errors 1`] = `Array []`; diff --git a/test/e2e/__snapshots__/headers.test.js.snap.webpack5 b/test/e2e/__snapshots__/headers.test.js.snap.webpack5 index c9edf9f641..2deab3832d 100644 --- a/test/e2e/__snapshots__/headers.test.js.snap.webpack5 +++ b/test/e2e/__snapshots__/headers.test.js.snap.webpack5 @@ -1,5 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`headers option as a function returning an array should handle GET request with headers: console messages 1`] = `Array []`; + +exports[`headers option as a function returning an array should handle GET request with headers: page errors 1`] = `Array []`; + +exports[`headers option as a function returning an array should handle GET request with headers: response headers x-bar 1`] = `"value2"`; + +exports[`headers option as a function returning an array should handle GET request with headers: response headers x-foo 1`] = `"value1"`; + +exports[`headers option as a function returning an array should handle GET request with headers: response status 1`] = `200`; + exports[`headers option as a function should handle GET request with headers as a function: console messages 1`] = `Array []`; exports[`headers option as a function should handle GET request with headers as a function: page errors 1`] = `Array []`; diff --git a/test/e2e/headers.test.js b/test/e2e/headers.test.js index 780c20d88d..8c1b216cdb 100644 --- a/test/e2e/headers.test.js +++ b/test/e2e/headers.test.js @@ -258,6 +258,78 @@ describe("headers option", () => { }); }); + describe("as a function returning an array", () => { + let compiler; + let server; + let page; + let browser; + let pageErrors; + let consoleMessages; + + beforeEach(async () => { + compiler = webpack(config); + + server = new Server( + { + headers: () => [ + { + key: "X-Foo", + value: "value1", + }, + { + key: "X-Bar", + value: "value2", + }, + ], + port, + }, + compiler + ); + + await server.start(); + + ({ page, browser } = await runBrowser()); + + pageErrors = []; + consoleMessages = []; + }); + + afterEach(async () => { + await browser.close(); + await server.stop(); + }); + + it("should handle GET request with headers", async () => { + page + .on("console", (message) => { + consoleMessages.push(message); + }) + .on("pageerror", (error) => { + pageErrors.push(error); + }); + + const response = await page.goto(`http://127.0.0.1:${port}/main.js`, { + waitUntil: "networkidle0", + }); + + expect(response.headers()["x-foo"]).toMatchSnapshot( + "response headers x-foo" + ); + + expect(response.headers()["x-bar"]).toMatchSnapshot( + "response headers x-bar" + ); + + expect(response.status()).toMatchSnapshot("response status"); + + expect(consoleMessages.map((message) => message.text())).toMatchSnapshot( + "console messages" + ); + + expect(pageErrors).toMatchSnapshot("page errors"); + }); + }); + describe("dev middleware headers take precedence for dev middleware output files", () => { let compiler; let server;