diff --git a/lib/Server.js b/lib/Server.js index 2d1850e8ec..ff21ccee94 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -68,16 +68,18 @@ if (semver.satisfies(process.version, '8.6.0 - 9')) { tls.DEFAULT_ECDH_CURVE = 'auto'; } -const STATS = { - all: false, - hash: true, - assets: true, - warnings: true, - errors: true, - errorDetails: false, -}; - class Server { + static get DEFAULT_STATS() { + return { + all: false, + hash: true, + assets: true, + warnings: true, + errors: true, + errorDetails: false, + }; + } + constructor(compiler, options = {}, _log) { this.log = _log || createLogger(options); @@ -87,6 +89,10 @@ class Server { throw new Error("'filename' option must be set in lazy mode."); } + this.stats = + options.stats && Object.keys(options.stats).length + ? options.stats + : Server.DEFAULT_STATS; this.hot = options.hot || options.hotOnly; this.headers = options.headers; this.progress = options.progress; @@ -140,7 +146,7 @@ class Server { compile.tap('webpack-dev-server', invalidPlugin); invalid.tap('webpack-dev-server', invalidPlugin); done.tap('webpack-dev-server', (stats) => { - this._sendStats(this.sockets, stats.toJson(STATS)); + this._sendStats(this.sockets, this.getStats(stats)); this._stats = stats; }); }; @@ -676,6 +682,10 @@ class Server { }, this); } + getStats(statsObj) { + return statsObj.toJson(this.stats); + } + use() { // eslint-disable-next-line this.app.use.apply(this.app, arguments); @@ -848,7 +858,7 @@ class Server { return; } - this._sendStats([connection], this._stats.toJson(STATS), true); + this._sendStats([connection], this.getStats(this._stats), true); }); socket.installHandlers(this.listeningApp, { diff --git a/lib/utils/createConfig.js b/lib/utils/createConfig.js index 53e00cf2af..8804571a1e 100644 --- a/lib/utils/createConfig.js +++ b/lib/utils/createConfig.js @@ -104,10 +104,10 @@ function createConfig(config, argv, { port }) { } if (!options.stats) { - options.stats = { + options.stats = defaultTo(firstWpOpt.stats, { cached: false, cachedAssets: false, - }; + }); } if ( diff --git a/test/CreateConfig.test.js b/test/CreateConfig.test.js index edeb0da422..f8bbb12209 100644 --- a/test/CreateConfig.test.js +++ b/test/CreateConfig.test.js @@ -3,6 +3,7 @@ const path = require('path'); const createConfig = require('../lib/utils/createConfig'); const webpackConfig = require('./fixtures/schema/webpack.config.simple'); +const webpackConfigNoStats = require('./fixtures/schema/webpack.config.no-dev-stats'); const argv = { port: 8080, @@ -853,4 +854,11 @@ describe('createConfig', () => { expect(config).toMatchSnapshot(); }); + + it('use webpack stats', () => { + expect( + createConfig(webpackConfigNoStats, argv, { port: 8080 }) + ).toMatchSnapshot(); + expect(webpackConfigNoStats).toMatchSnapshot(); + }); }); diff --git a/test/Server.test.js b/test/Server.test.js new file mode 100644 index 0000000000..12faa3ff4c --- /dev/null +++ b/test/Server.test.js @@ -0,0 +1,73 @@ +'use strict'; + +const webpack = require('webpack'); +const Server = require('../lib/Server'); +const config = require('./fixtures/simple-config/webpack.config'); + +const allStats = [ + {}, + // eslint-disable-next-line no-undefined + undefined, + false, + 'errors-only', + { + assets: false, + }, +]; + +describe('Server', () => { + it(`should cascade stats options`, () => { + return new Promise((resolve, reject) => { + (function iterate(stats, i) { + if (i === allStats.length) { + return resolve(); + } + + const prom = new Promise((res, rej) => { + const compiler = webpack(config); + const server = new Server(compiler, { stats }); + + compiler.hooks.done.tap('webpack-dev-server', (s) => { + const finalStats = JSON.stringify(server.getStats(s)); + const defaultStats = JSON.stringify( + server._stats.toJson(Server.DEFAULT_STATS) + ); + + // If we're not over-riding stats configuration, + // we get the same result as the DEFAULT_STATS + if (!stats || !Object.keys(stats).length) { + try { + expect(finalStats).toBe(defaultStats); + } catch (e) { + rej(e); + } + } else { + try { + expect(finalStats).not.toBe(defaultStats); + } catch (e) { + rej(e); + } + } + + server.close(() => { + res(); + }); + }); + + compiler.run(() => {}); + server.listen(8080, 'localhost'); + }); + + // Iterate to cover each case. + prom + .then(() => { + i += 1; + iterate(allStats[i], i); + }) + .catch((e) => { + reject(e); + }); + })(allStats[0], 0); + }); + }); +}); diff --git a/test/__snapshots__/CreateConfig.test.js.snap b/test/__snapshots__/CreateConfig.test.js.snap index c66f9ab9de..2c631ecd42 100644 --- a/test/__snapshots__/CreateConfig.test.js.snap +++ b/test/__snapshots__/CreateConfig.test.js.snap @@ -1037,6 +1037,77 @@ Object { } `; +exports[`createConfig use webpack stats 1`] = ` +Object { + "clientLogLevel": "_clientLogLevel", + "compress": "_compress", + "contentBase": "_contentBase", + "disableHostCheck": "_disableHostCheck", + "filename": "_filename", + "historyApiFallback": "_historyApiFallback", + "host": "_foo", + "hot": "_hot", + "hotOnly": "_hotOnly", + "https": "_https", + "inline": "_inline", + "lazy": "_lazy", + "noInfo": true, + "open": "_open", + "openPage": "_openPage", + "pfxPassphrase": "_pfxPassphrase", + "port": "_port", + "progress": "_progress", + "public": "_public", + "publicPath": "_publicPath", + "quiet": "_quiet", + "socket": "_socket", + "stats": Object { + "assetsSort": "size", + }, + "useLocalIp": "_useLocalIp", + "watchContentBase": "_watchContentBase", +} +`; + +exports[`createConfig use webpack stats 2`] = ` +Object { + "devServer": Object { + "clientLogLevel": "_clientLogLevel", + "compress": "_compress", + "contentBase": "_contentBase", + "disableHostCheck": "_disableHostCheck", + "filename": "_filename", + "historyApiFallback": "_historyApiFallback", + "host": "_foo", + "hot": "_hot", + "hotOnly": "_hotOnly", + "https": "_https", + "inline": "_inline", + "lazy": "_lazy", + "noInfo": true, + "open": "_open", + "openPage": "_openPage", + "pfxPassphrase": "_pfxPassphrase", + "port": "_port", + "progress": "_progress", + "public": "_public", + "publicPath": "_publicPath", + "quiet": "_quiet", + "socket": "_socket", + "stats": Object { + "assetsSort": "size", + }, + "useLocalIp": "_useLocalIp", + "watchContentBase": "_watchContentBase", + }, + "entry": "./app.js", + "mode": "development", + "stats": Object { + "assetsSort": "size", + }, +} +`; + exports[`createConfig useLocalIp option (in devServer config) 1`] = ` Object { "hot": true, diff --git a/test/fixtures/schema/webpack.config.no-dev-stats.js b/test/fixtures/schema/webpack.config.no-dev-stats.js new file mode 100644 index 0000000000..ca5a83b7da --- /dev/null +++ b/test/fixtures/schema/webpack.config.no-dev-stats.js @@ -0,0 +1,34 @@ +'use strict'; + +module.exports = { + entry: './app.js', + stats: { + assetsSort: 'size', + }, + devServer: { + host: '_foo', + public: '_public', + socket: '_socket', + progress: '_progress', + publicPath: '_publicPath', + filename: '_filename', + hot: '_hot', + hotOnly: '_hotOnly', + clientLogLevel: '_clientLogLevel', + contentBase: '_contentBase', + watchContentBase: '_watchContentBase', + lazy: '_lazy', + noInfo: '_noInfo', + quiet: '_quiet', + https: '_https', + pfxPassphrase: '_pfxPassphrase', + inline: '_inline', + historyApiFallback: '_historyApiFallback', + compress: '_compress', + disableHostCheck: '_disableHostCheck', + open: '_open', + openPage: '_openPage', + useLocalIp: '_useLocalIp', + port: '_port', + }, +};