Skip to content

Commit 9911437

Browse files
authored
feat: allow array for headers option (#3847)
1 parent 71da079 commit 9911437

11 files changed

+320
-9
lines changed

examples/headers/array/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# headers option as an object
2+
3+
Adds headers to all responses.
4+
5+
**webpack.config.js**
6+
7+
```js
8+
module.exports = {
9+
// ...
10+
devServer: {
11+
headers: [
12+
{
13+
key: "X-Foo",
14+
value: "value1",
15+
},
16+
{
17+
key: "X-Bar",
18+
value: "value2",
19+
},
20+
],
21+
},
22+
};
23+
```
24+
25+
To run this example use the following command:
26+
27+
```console
28+
npx webpack serve --open
29+
```
30+
31+
## What should happen
32+
33+
1. The script should open `http://localhost:8080/`.
34+
2. You should see the text on the page itself change to read `Success!`.
35+
3. Open the console in your browser's devtools and select the _Network_ tab.
36+
4. Find `main.js`. The response headers should contain `X-Foo: value1` and `X-Bar: value2`.

examples/headers/array/app.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"use strict";
2+
3+
const target = document.querySelector("#target");
4+
5+
target.classList.add("pass");
6+
target.innerHTML = "Success!";
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"use strict";
2+
3+
// our setup function adds behind-the-scenes bits to the config that all of our
4+
// examples need
5+
const { setup } = require("../../util");
6+
7+
module.exports = setup({
8+
context: __dirname,
9+
entry: "./app.js",
10+
devServer: {
11+
headers: [
12+
{
13+
key: "X-Foo",
14+
value: "value1",
15+
},
16+
{
17+
key: "X-Bar",
18+
value: "value2",
19+
},
20+
],
21+
},
22+
});

lib/Server.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,10 +1845,19 @@ class Server {
18451845
headers = headers(req, res, this.middleware.context);
18461846
}
18471847

1848-
// eslint-disable-next-line guard-for-in
1849-
for (const name in headers) {
1850-
res.setHeader(name, headers[name]);
1848+
const allHeaders = [];
1849+
1850+
if (!Array.isArray(headers)) {
1851+
// eslint-disable-next-line guard-for-in
1852+
for (const name in headers) {
1853+
allHeaders.push({ key: name, value: headers[name] });
1854+
}
1855+
headers = allHeaders;
18511856
}
1857+
1858+
headers.forEach((header) => {
1859+
res.setHeader(header.key, header.value);
1860+
});
18521861
}
18531862

18541863
next();

lib/options.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,32 @@
369369
"description": "Allows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP).",
370370
"link": "https://webpack.js.org/configuration/dev-server/#devserverhttps"
371371
},
372+
"HeaderObject": {
373+
"type": "object",
374+
"additionalProperties": false,
375+
"properties": {
376+
"key": {
377+
"description": "key of header.",
378+
"type": "string"
379+
},
380+
"value": {
381+
"description": "value of header.",
382+
"type": "string"
383+
}
384+
},
385+
"cli": {
386+
"exclude": true
387+
}
388+
},
372389
"Headers": {
373390
"anyOf": [
391+
{
392+
"type": "array",
393+
"items": {
394+
"$ref": "#/definitions/HeaderObject"
395+
},
396+
"minItems": 1
397+
},
374398
{
375399
"type": "object"
376400
},

test/__snapshots__/validate-options.test.js.snap.webpack4

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,26 @@ exports[`options validate should throw an error on the "devMiddleware" option wi
223223
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverdevmiddleware"
224224
`;
225225

226+
exports[`options validate should throw an error on the "headers" option with '[]' value 1`] = `
227+
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
228+
- options.headers should be a non-empty array."
229+
`;
230+
231+
exports[`options validate should throw an error on the "headers" option with '[{"foo":"bar"}]' value 1`] = `
232+
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
233+
- options.headers[0] has an unknown property 'foo'. These properties are valid:
234+
object { key?, value? }"
235+
`;
236+
226237
exports[`options validate should throw an error on the "headers" option with '1' value 1`] = `
227238
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
228239
- options.headers should be one of these:
229-
object { … } | function
240+
[object { key?, value? }, ...] (should not have fewer than 1 item) | object { … } | function
230241
-> Allows to set custom headers on response.
231242
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverheaders
232243
Details:
244+
* options.headers should be an array:
245+
[object { key?, value? }, ...] (should not have fewer than 1 item)
233246
* options.headers should be an object:
234247
object { … }
235248
* options.headers should be an instance of function."
@@ -238,10 +251,12 @@ exports[`options validate should throw an error on the "headers" option with '1'
238251
exports[`options validate should throw an error on the "headers" option with 'false' value 1`] = `
239252
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
240253
- options.headers should be one of these:
241-
object { … } | function
254+
[object { key?, value? }, ...] (should not have fewer than 1 item) | object { … } | function
242255
-> Allows to set custom headers on response.
243256
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverheaders
244257
Details:
258+
* options.headers should be an array:
259+
[object { key?, value? }, ...] (should not have fewer than 1 item)
245260
* options.headers should be an object:
246261
object { … }
247262
* options.headers should be an instance of function."

test/__snapshots__/validate-options.test.js.snap.webpack5

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,26 @@ exports[`options validate should throw an error on the "devMiddleware" option wi
223223
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverdevmiddleware"
224224
`;
225225

226+
exports[`options validate should throw an error on the "headers" option with '[]' value 1`] = `
227+
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
228+
- options.headers should be a non-empty array."
229+
`;
230+
231+
exports[`options validate should throw an error on the "headers" option with '[{"foo":"bar"}]' value 1`] = `
232+
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
233+
- options.headers[0] has an unknown property 'foo'. These properties are valid:
234+
object { key?, value? }"
235+
`;
236+
226237
exports[`options validate should throw an error on the "headers" option with '1' value 1`] = `
227238
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
228239
- options.headers should be one of these:
229-
object { … } | function
240+
[object { key?, value? }, ...] (should not have fewer than 1 item) | object { … } | function
230241
-> Allows to set custom headers on response.
231242
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverheaders
232243
Details:
244+
* options.headers should be an array:
245+
[object { key?, value? }, ...] (should not have fewer than 1 item)
233246
* options.headers should be an object:
234247
object { … }
235248
* options.headers should be an instance of function."
@@ -238,10 +251,12 @@ exports[`options validate should throw an error on the "headers" option with '1'
238251
exports[`options validate should throw an error on the "headers" option with 'false' value 1`] = `
239252
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
240253
- options.headers should be one of these:
241-
object { … } | function
254+
[object { key?, value? }, ...] (should not have fewer than 1 item) | object { … } | function
242255
-> Allows to set custom headers on response.
243256
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverheaders
244257
Details:
258+
* options.headers should be an array:
259+
[object { key?, value? }, ...] (should not have fewer than 1 item)
245260
* options.headers should be an object:
246261
object { … }
247262
* options.headers should be an instance of function."

test/e2e/__snapshots__/headers.test.js.snap.webpack4

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`headers option as a function returning an array should handle GET request with headers: console messages 1`] = `Array []`;
4+
5+
exports[`headers option as a function returning an array should handle GET request with headers: page errors 1`] = `Array []`;
6+
7+
exports[`headers option as a function returning an array should handle GET request with headers: response headers x-bar 1`] = `"value2"`;
8+
9+
exports[`headers option as a function returning an array should handle GET request with headers: response headers x-foo 1`] = `"value1"`;
10+
11+
exports[`headers option as a function returning an array should handle GET request with headers: response status 1`] = `200`;
12+
313
exports[`headers option as a function should handle GET request with headers as a function: console messages 1`] = `Array []`;
414

515
exports[`headers option as a function should handle GET request with headers as a function: page errors 1`] = `Array []`;
@@ -19,6 +29,16 @@ exports[`headers option as a string should handle GET request with headers: resp
1929

2030
exports[`headers option as a string should handle GET request with headers: response status 1`] = `200`;
2131

32+
exports[`headers option as an array of objects should handle GET request with headers: console messages 1`] = `Array []`;
33+
34+
exports[`headers option as an array of objects should handle GET request with headers: page errors 1`] = `Array []`;
35+
36+
exports[`headers option as an array of objects should handle GET request with headers: response headers x-bar 1`] = `"value2"`;
37+
38+
exports[`headers option as an array of objects should handle GET request with headers: response headers x-foo 1`] = `"value1"`;
39+
40+
exports[`headers option as an array of objects should handle GET request with headers: response status 1`] = `200`;
41+
2242
exports[`headers option as an array should handle GET request with headers as an array: console messages 1`] = `Array []`;
2343

2444
exports[`headers option as an array should handle GET request with headers as an array: page errors 1`] = `Array []`;

test/e2e/__snapshots__/headers.test.js.snap.webpack5

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`headers option as a function returning an array should handle GET request with headers: console messages 1`] = `Array []`;
4+
5+
exports[`headers option as a function returning an array should handle GET request with headers: page errors 1`] = `Array []`;
6+
7+
exports[`headers option as a function returning an array should handle GET request with headers: response headers x-bar 1`] = `"value2"`;
8+
9+
exports[`headers option as a function returning an array should handle GET request with headers: response headers x-foo 1`] = `"value1"`;
10+
11+
exports[`headers option as a function returning an array should handle GET request with headers: response status 1`] = `200`;
12+
313
exports[`headers option as a function should handle GET request with headers as a function: console messages 1`] = `Array []`;
414

515
exports[`headers option as a function should handle GET request with headers as a function: page errors 1`] = `Array []`;
@@ -19,6 +29,16 @@ exports[`headers option as a string should handle GET request with headers: resp
1929

2030
exports[`headers option as a string should handle GET request with headers: response status 1`] = `200`;
2131

32+
exports[`headers option as an array of objects should handle GET request with headers: console messages 1`] = `Array []`;
33+
34+
exports[`headers option as an array of objects should handle GET request with headers: page errors 1`] = `Array []`;
35+
36+
exports[`headers option as an array of objects should handle GET request with headers: response headers x-bar 1`] = `"value2"`;
37+
38+
exports[`headers option as an array of objects should handle GET request with headers: response headers x-foo 1`] = `"value1"`;
39+
40+
exports[`headers option as an array of objects should handle GET request with headers: response status 1`] = `200`;
41+
2242
exports[`headers option as an array should handle GET request with headers as an array: console messages 1`] = `Array []`;
2343

2444
exports[`headers option as an array should handle GET request with headers as an array: page errors 1`] = `Array []`;

0 commit comments

Comments
 (0)