Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions lib/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -851,10 +851,14 @@ class Server {
}

setContentHeaders(req, res, next) {
if (this.options.headers) {
let { headers } = this.options;
if (headers) {
if (typeof headers === 'function') {
headers = headers(req, res, this.middleware.context);
}
// eslint-disable-next-line guard-for-in
for (const name in this.options.headers) {
res.setHeader(name, this.options.headers[name]);
for (const name in headers) {
res.setHeader(name, headers[name]);
}
}

Expand Down
9 changes: 8 additions & 1 deletion lib/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,14 @@
"description": "Defines routes which are enabled by default, on by default and allows localhost. https://webpack.js.org/configuration/dev-server/#devserverfirewall"
},
"headers": {
"type": "object",
"anyOf": [
{
"type": "object"
},
{
"instanceof": "Function"
}
],
"description": "Adds headers to all responses. https://webpack.js.org/configuration/dev-server/#devserverheaders"
},
"historyApiFallback": {
Expand Down
21 changes: 18 additions & 3 deletions test/__snapshots__/validate-options.test.js.snap.webpack4
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,26 @@ exports[`options validate should throw an error on the "firewall" option with '[
- configuration.firewall should be an non-empty array."
`;

exports[`options validate should throw an error on the "headers" option with '1' value 1`] = `
"ValidationError: Invalid configuration object. Object has been initialized using a configuration object that does not match the API schema.
- configuration.headers should be one of these:
object { … } | function
-> Adds headers to all responses. https://webpack.js.org/configuration/dev-server/#devserverheaders
Details:
* configuration.headers should be an object:
object { … }
* configuration.headers should be an instance of function."
`;

exports[`options validate should throw an error on the "headers" option with 'false' value 1`] = `
"ValidationError: Invalid configuration object. Object has been initialized using a configuration object that does not match the API schema.
- configuration.headers should be an object:
object { … }
-> Adds headers to all responses. https://webpack.js.org/configuration/dev-server/#devserverheaders"
- configuration.headers should be one of these:
object { … } | function
-> Adds headers to all responses. https://webpack.js.org/configuration/dev-server/#devserverheaders
Details:
* configuration.headers should be an object:
object { … }
* configuration.headers should be an instance of function."
`;

exports[`options validate should throw an error on the "historyApiFallback" option with '' value 1`] = `
Expand Down
21 changes: 18 additions & 3 deletions test/__snapshots__/validate-options.test.js.snap.webpack5
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,26 @@ exports[`options validate should throw an error on the "firewall" option with '[
- configuration.firewall should be an non-empty array."
`;

exports[`options validate should throw an error on the "headers" option with '1' value 1`] = `
"ValidationError: Invalid configuration object. Object has been initialized using a configuration object that does not match the API schema.
- configuration.headers should be one of these:
object { … } | function
-> Adds headers to all responses. https://webpack.js.org/configuration/dev-server/#devserverheaders
Details:
* configuration.headers should be an object:
object { … }
* configuration.headers should be an instance of function."
`;

exports[`options validate should throw an error on the "headers" option with 'false' value 1`] = `
"ValidationError: Invalid configuration object. Object has been initialized using a configuration object that does not match the API schema.
- configuration.headers should be an object:
object { … }
-> Adds headers to all responses. https://webpack.js.org/configuration/dev-server/#devserverheaders"
- configuration.headers should be one of these:
object { … } | function
-> Adds headers to all responses. https://webpack.js.org/configuration/dev-server/#devserverheaders
Details:
* configuration.headers should be an object:
object { … }
* configuration.headers should be an instance of function."
`;

exports[`options validate should throw an error on the "historyApiFallback" option with '' value 1`] = `
Expand Down
26 changes: 26 additions & 0 deletions test/server/headers-option.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,32 @@ describe('headers option', () => {
});
});

describe('as a function', () => {
beforeAll((done) => {
server = testServer.start(
config,
{
headers: () => {return { 'X-Bar': ['key1=value1', 'key2=value2'] }},
port,
},
done
);
req = request(server.app);
});

afterAll(testServer.close);

it('GET request with headers as a function', (done) => {
// https://github.com/webpack/webpack-dev-server/pull/1650#discussion_r254217027
const expected = ['v7', 'v8', 'v9'].includes(
process.version.split('.')[0]
)
? 'key1=value1,key2=value2'
: 'key1=value1, key2=value2';
req.get('/main').expect('X-Bar', expected).expect(200, done);
});
});

describe('dev middleware headers take precedence for dev middleware output files', () => {
beforeAll((done) => {
server = testServer.start(
Expand Down
4 changes: 2 additions & 2 deletions test/validate-options.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ const tests = {
failure: ['', []],
},
headers: {
success: [{}, { foo: 'bar' }],
failure: [false],
success: [{}, { foo: 'bar' }, () => {}],
failure: [false, 1],
},
historyApiFallback: {
success: [{}, true],
Expand Down