diff --git a/bin/options.js b/bin/options.js index 3c46d9be9f..424ac2a21a 100644 --- a/bin/options.js +++ b/bin/options.js @@ -37,6 +37,10 @@ const options = { describe: 'Inline mode (set to false to disable including client scripts like livereload)', }, + profile: { + type: 'boolean', + describe: 'Print compilation profile data for progress steps', + }, progress: { type: 'boolean', describe: 'Print compilation progress in percentage', diff --git a/bin/webpack-dev-server.js b/bin/webpack-dev-server.js index deb015f6f1..26de7d4ba6 100755 --- a/bin/webpack-dev-server.js +++ b/bin/webpack-dev-server.js @@ -97,12 +97,6 @@ function startDevServer(config, options) { throw err; } - if (options.progress) { - new webpack.ProgressPlugin({ - profile: argv.profile, - }).apply(compiler); - } - try { server = new Server(compiler, options, log); } catch (err) { diff --git a/lib/Server.js b/lib/Server.js index 5425f7be31..4b343e212f 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -91,6 +91,7 @@ class Server { // TODO this. is deprecated (remove them in next major release.) in favor this.options. this.hot = this.options.hot || this.options.hotOnly; this.headers = this.options.headers; + this.profile = !!this.options.profile; this.progress = this.options.progress; this.serveIndex = this.options.serveIndex; @@ -147,6 +148,10 @@ class Server { } setupProgressPlugin() { + new webpack.ProgressPlugin({ + profile: this.profile, + }).apply(this.compiler); + const progressPlugin = new webpack.ProgressPlugin( (percent, msg, addInfo) => { percent = Math.floor(percent * 100); diff --git a/lib/options.json b/lib/options.json index 7e8aba1924..6531af88c6 100644 --- a/lib/options.json +++ b/lib/options.json @@ -255,6 +255,9 @@ } ] }, + "profile": { + "type": "boolean" + }, "progress": { "type": "boolean" }, @@ -422,6 +425,7 @@ "pfx": "should be {String|Buffer} (https://webpack.js.org/configuration/dev-server/#devserverpfx)", "pfxPassphrase": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverpfxpassphrase)", "port": "should be {Number|String|Null} (https://webpack.js.org/configuration/dev-server/#devserverport)", + "profile": "should be {Boolean}", "progress": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverprogress---cli-only)", "proxy": "should be {Object|Array} (https://webpack.js.org/configuration/dev-server/#devserverproxy)", "public": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverpublic)", diff --git a/lib/utils/createConfig.js b/lib/utils/createConfig.js index e7f9bf799e..c6158549cb 100644 --- a/lib/utils/createConfig.js +++ b/lib/utils/createConfig.js @@ -46,6 +46,10 @@ function createConfig(config, argv, { port }) { options.liveReload = false; } + if (argv.profile) { + options.profile = argv.profile; + } + if (argv.progress) { options.progress = argv.progress; } diff --git a/test/cli.test.js b/test/cli.test.js index d9b7b72b41..61f4e0ea61 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -20,6 +20,23 @@ describe('CLI', () => { .then((output) => { expect(output.code).toEqual(0); expect(output.stderr.includes('0% compiling')).toBe(true); + // should not profile + expect( + output.stderr.includes('ms after chunk modules optimization') + ).toBe(false); + done(); + }) + .catch(done); + }); + + it('--progress --profile', (done) => { + testBin('--progress --profile') + .then((output) => { + expect(output.code).toEqual(0); + // should profile + expect( + output.stderr.includes('ms after chunk modules optimization') + ).toBe(true); done(); }) .catch(done); diff --git a/test/e2e/Progress.test.js b/test/e2e/Progress.test.js new file mode 100644 index 0000000000..7917179ff0 --- /dev/null +++ b/test/e2e/Progress.test.js @@ -0,0 +1,62 @@ +'use strict'; + +/* eslint-disable + no-undef +*/ +const fs = require('fs'); +const path = require('path'); +const testServer = require('../helpers/test-server'); +const reloadConfig = require('../fixtures/reload-config/webpack.config'); +const runBrowser = require('../helpers/run-browser'); + +describe('client progress', () => { + describe('using hot', () => { + const cssFilePath = path.resolve(__dirname, '../temp/main.css'); + beforeAll((done) => { + fs.writeFileSync( + cssFilePath, + 'body { background-color: rgb(0, 0, 255); }' + ); + const options = { + port: 9000, + host: '0.0.0.0', + inline: true, + hot: true, + progress: true, + watchOptions: { + poll: 500, + }, + }; + testServer.startAwaitingCompilation(reloadConfig, options, done); + }); + + afterAll((done) => { + testServer.close(done); + }); + + describe('on browser client', () => { + jest.setTimeout(30000); + + it('should console.log progress', (done) => { + runBrowser().then(({ page, browser }) => { + const res = []; + page.waitForNavigation({ waitUntil: 'load' }).then(() => { + fs.writeFileSync( + cssFilePath, + 'body { background-color: rgb(255, 0, 0); }' + ); + page.waitFor(10000).then(() => { + expect(res).toMatchSnapshot(); + browser.close().then(done); + }); + }); + + page.goto('http://localhost:9000/main'); + page.on('console', ({ _text }) => { + res.push(_text); + }); + }); + }); + }); + }); +}); diff --git a/test/e2e/__snapshots__/Progress.test.js.snap b/test/e2e/__snapshots__/Progress.test.js.snap new file mode 100644 index 0000000000..ecb9b79b94 --- /dev/null +++ b/test/e2e/__snapshots__/Progress.test.js.snap @@ -0,0 +1,98 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`client progress using hot on browser client should console.log progress 1`] = ` +Array [ + "[HMR] Waiting for update signal from WDS...", + "[WDS] Hot Module Replacement enabled.", + "[WDS] Live Reloading enabled.", + "[WDS] App updated. Recompiling...", + "[WDS] 0% - compiling.", + "[WDS] 10% - building (0/0 modules).", + "[WDS] 10% - building (0/0 modules).", + "[WDS] 10% - building (0/1 modules).", + "[WDS] 40% - building (0/1 modules).", + "[WDS] 40% - building (1/1 modules).", + "[WDS] 70% - building (1/1 modules).", + "[WDS] 70% - finish module graph.", + "[WDS] 70% - finish module graph (FlagDependencyExportsPlugin).", + "[WDS] 70% - sealing.", + "[WDS] 70% - sealing (WarnCaseSensitiveModulesPlugin).", + "[WDS] 71% - basic dependencies optimization.", + "[WDS] 72% - dependencies optimization.", + "[WDS] 72% - advanced dependencies optimization.", + "[WDS] 73% - after dependencies optimization.", + "[WDS] 70% - chunk graph.", + "[WDS] 71% - after chunk graph.", + "[WDS] 71% - after chunk graph (WebAssemblyModulesPlugin).", + "[WDS] 73% - optimizing.", + "[WDS] 74% - basic module optimization.", + "[WDS] 74% - module optimization.", + "[WDS] 75% - advanced module optimization.", + "[WDS] 75% - after module optimization.", + "[WDS] 76% - basic chunk optimization.", + "[WDS] 76% - basic chunk optimization (EnsureChunkConditionsPlugin).", + "[WDS] 76% - basic chunk optimization (RemoveParentModulesPlugin).", + "[WDS] 76% - basic chunk optimization (RemoveEmptyChunksPlugin).", + "[WDS] 76% - basic chunk optimization (MergeDuplicateChunksPlugin).", + "[WDS] 76% - chunk optimization.", + "[WDS] 77% - advanced chunk optimization.", + "[WDS] 77% - advanced chunk optimization (SplitChunksPlugin).", + "[WDS] 77% - advanced chunk optimization (RemoveEmptyChunksPlugin).", + "[WDS] 77% - after chunk optimization.", + "[WDS] 78% - module and chunk tree optimization.", + "[WDS] 78% - after module and chunk tree optimization.", + "[WDS] 79% - basic chunk modules optimization.", + "[WDS] 79% - chunk modules optimization.", + "[WDS] 80% - advanced chunk modules optimization.", + "[WDS] 80% - after chunk modules optimization.", + "[WDS] 81% - module reviving.", + "[WDS] 81% - module reviving (RecordIdsPlugin).", + "[WDS] 81% - module order optimization.", + "[WDS] 82% - advanced module order optimization.", + "[WDS] 82% - before module ids.", + "[WDS] 82% - before module ids (NamedModulesPlugin).", + "[WDS] 83% - module ids.", + "[WDS] 83% - module id optimization.", + "[WDS] 84% - module id optimization.", + "[WDS] 84% - chunk reviving.", + "[WDS] 84% - chunk reviving (RecordIdsPlugin).", + "[WDS] 85% - chunk order optimization.", + "[WDS] 85% - chunk order optimization (OccurrenceOrderChunkIdsPlugin).", + "[WDS] 85% - before chunk ids.", + "[WDS] 85% - before chunk ids (NamedChunksPlugin).", + "[WDS] 86% - chunk id optimization.", + "[WDS] 86% - after chunk id optimization.", + "[WDS] 87% - record modules.", + "[WDS] 87% - record modules (RecordIdsPlugin).", + "[WDS] 87% - record chunks.", + "[WDS] 87% - record chunks (RecordIdsPlugin).", + "[WDS] 88% - hashing.", + "[WDS] 88% - content hashing.", + "[WDS] 88% - content hashing (JavascriptModulesPlugin).", + "[WDS] 89% - after hashing.", + "[WDS] 89% - after hashing (HotModuleReplacementPlugin).", + "[WDS] 89% - record hash.", + "[WDS] 90% - module assets processing.", + "[WDS] 90% - chunk assets processing.", + "[WDS] 91% - additional chunk assets processing.", + "[WDS] 91% - additional chunk assets processing (HotModuleReplacementPlugin).", + "[WDS] 91% - recording.", + "[WDS] 91% - recording (HotModuleReplacementPlugin).", + "[WDS] 92% - additional asset processing.", + "[WDS] 92% - chunk asset optimization.", + "[WDS] 93% - after chunk asset optimization.", + "[WDS] 93% - asset optimization.", + "[WDS] 94% - after asset optimization.", + "[WDS] 94% - after seal.", + "[WDS] 95% - emitting.", + "[WDS] 98% - after emitting.", + "[WDS] 100% - Compilation completed.", + "[WDS] App hot update...", + "[HMR] Checking for updates on the server...", + "[HMR] Updated modules:", + "[HMR] - ../../temp/main.css", + "[HMR] - ../../../node_modules/css-loader/dist/cjs.js!../../temp/main.css", + "", + "[HMR] App is up to date.", +] +`; diff --git a/test/options.test.js b/test/options.test.js index b9d5c0a278..52567a8f6e 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -303,6 +303,10 @@ describe('options', () => { success: ['', 0, null], failure: [false], }, + profile: { + success: [false], + failure: [''], + }, progress: { success: [false], failure: [''],