From 32bc877f378af5fbf893d9e152369ed68ab127ee Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Fri, 21 May 2021 20:57:37 +0530 Subject: [PATCH] fix: improve processing of CLI flags (#3313) --- README.md | 2 +- bin/cli-flags.js | 64 ++++++++++--------- .../__snapshots__/cli.test.js.snap.webpack4 | 12 +++- .../__snapshots__/cli.test.js.snap.webpack5 | 12 +++- test/cli/cli.test.js | 52 +++++++++++++++ 5 files changed, 106 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 61f729a7c2..09618b2aa7 100644 --- a/README.md +++ b/README.md @@ -114,12 +114,12 @@ Options: --no-client-progress Do not print compilation progress in percentage in the browser. --client-overlay Show a full-screen overlay in the browser when there are compiler errors or warnings. --no-client-overlay Do not show a full-screen overlay in the browser when there are compiler errors or warnings. + --client-logging Log level in the browser (none, error, warn, info, log, verbose). --open [value...] Open the default browser. --no-open Do not open the default browser. --open-app Open specified browser. --open-target [value...] Open specified route in browser. --no-open-target Do not open specified route in browser. - --client-logging Log level in the browser (none, error, warn, info, log, verbose). --history-api-fallback Fallback to /index.html for Single Page Applications. --no-history-api-fallback Do not fallback to /index.html for Single Page Applications. --compress Enable gzip compression. diff --git a/bin/cli-flags.js b/bin/cli-flags.js index ab95de4324..36986734b9 100644 --- a/bin/cli-flags.js +++ b/bin/cli-flags.js @@ -1,5 +1,7 @@ 'use strict'; +const normalizeOption = (option) => (typeof option === 'object' ? option : {}); + module.exports = { devServer: [ { @@ -47,7 +49,7 @@ module.exports = { ], description: 'Directory for static contents.', processor(opts) { - opts.static = opts.static || {}; + opts.static = normalizeOption(opts.static); opts.static.directory = opts.staticDirectory; delete opts.staticDirectory; }, @@ -64,7 +66,7 @@ module.exports = { 'The bundled files will be available in the browser under this path.', multiple: true, processor(opts) { - opts.static = opts.static || {}; + opts.static = normalizeOption(opts.static); opts.static.publicPath = opts.staticPublicPath; delete opts.staticPublicPath; }, @@ -82,7 +84,7 @@ module.exports = { 'Do not tell dev-server to use serveIndex middleware.', negative: true, processor(opts) { - opts.static = opts.static || {}; + opts.static = normalizeOption(opts.static); opts.static.serveIndex = opts.staticServeIndex; delete opts.staticServeIndex; }, @@ -99,7 +101,7 @@ module.exports = { negatedDescription: 'Do not watch for files in static content directory.', negative: true, processor(opts) { - opts.static = opts.static || {}; + opts.static = normalizeOption(opts.static); opts.static.watch = opts.staticWatch; delete opts.staticWatch; }, @@ -138,7 +140,7 @@ module.exports = { ], description: 'Passphrase for a pfx file.', processor(opts) { - opts.https = opts.https || {}; + opts.https = normalizeOption(opts.https); opts.https.passphrase = opts.httpsPassphrase; delete opts.httpsPassphrase; }, @@ -153,7 +155,7 @@ module.exports = { ], description: 'Path to an SSL key.', processor(opts) { - opts.https = opts.https || {}; + opts.https = normalizeOption(opts.https); opts.https.key = opts.httpsKey; delete opts.httpsKey; }, @@ -168,7 +170,7 @@ module.exports = { ], description: 'Path to an SSL pfx file.', processor(opts) { - opts.https = opts.https || {}; + opts.https = normalizeOption(opts.https); opts.https.pfx = opts.httpsPfx; delete opts.httpsPfx; }, @@ -183,7 +185,7 @@ module.exports = { ], description: 'Path to an SSL certificate.', processor(opts) { - opts.https = opts.https || {}; + opts.https = normalizeOption(opts.https); opts.https.cert = opts.httpsCert; delete opts.httpsCert; }, @@ -198,7 +200,7 @@ module.exports = { ], description: 'Path to an SSL CA certificate.', processor(opts) { - opts.https = opts.https || {}; + opts.https = normalizeOption(opts.https); opts.https.cacert = opts.httpsCacert; delete opts.httpsCacert; }, @@ -214,7 +216,7 @@ module.exports = { description: 'Request for an SSL certificate.', negatedDescription: 'Do not request for an SSL certificate.', processor(opts) { - opts.https = opts.https || {}; + opts.https = normalizeOption(opts.https); opts.https.requestCert = opts.httpsRequestCert; delete opts.httpsRequestCert; }, @@ -257,7 +259,7 @@ module.exports = { 'Do not tell devServer to inject a Hot Module Replacement entry.', negative: true, processor(opts) { - opts.client = opts.client || {}; + opts.client = normalizeOption(opts.client); opts.client.hotEntry = opts.clientHotEntry; delete opts.clientHotEntry; }, @@ -275,7 +277,7 @@ module.exports = { 'Do not print compilation progress in percentage in the browser.', negative: true, processor(opts) { - opts.client = opts.client || {}; + opts.client = normalizeOption(opts.client); opts.client.progress = opts.clientProgress; delete opts.clientProgress; }, @@ -294,11 +296,27 @@ module.exports = { 'Do not show a full-screen overlay in the browser when there are compiler errors or warnings.', negative: true, processor(opts) { - opts.client = opts.client || {}; + opts.client = normalizeOption(opts.client); opts.client.overlay = opts.clientOverlay; delete opts.clientOverlay; }, }, + { + name: 'client-logging', + type: String, + configs: [ + { + type: 'string', + }, + ], + description: + 'Log level in the browser (none, error, warn, info, log, verbose).', + processor(opts) { + opts.client = normalizeOption(opts.client); + opts.client.logging = opts.clientLogging; + delete opts.clientLogging; + }, + }, { name: 'open', type: [Boolean, String], @@ -325,7 +343,7 @@ module.exports = { ], description: 'Open specified browser.', processor(opts) { - opts.open = opts.open || {}; + opts.open = normalizeOption(opts.open); opts.open.app = opts.openApp; delete opts.openApp; }, @@ -343,7 +361,7 @@ module.exports = { ], description: 'Open specified route in browser.', processor(opts) { - opts.open = opts.open || {}; + opts.open = normalizeOption(opts.open); opts.open.target = opts.openTarget; delete opts.openTarget; }, @@ -351,22 +369,6 @@ module.exports = { multiple: true, negative: true, }, - { - name: 'client-logging', - type: String, - configs: [ - { - type: 'string', - }, - ], - description: - 'Log level in the browser (none, error, warn, info, log, verbose).', - processor(opts) { - opts.client = opts.client || {}; - opts.client.logging = opts.clientLogging; - delete opts.clientLogging; - }, - }, { name: 'history-api-fallback', type: Boolean, diff --git a/test/cli/__snapshots__/cli.test.js.snap.webpack4 b/test/cli/__snapshots__/cli.test.js.snap.webpack4 index dbb63881a5..917825ddfd 100644 --- a/test/cli/__snapshots__/cli.test.js.snap.webpack4 +++ b/test/cli/__snapshots__/cli.test.js.snap.webpack4 @@ -164,6 +164,14 @@ exports[`CLI --no-https-request-cert 1`] = ` [webpack-dev-server] Content not from webpack is served from '/public' directory" `; +exports[`CLI https and other related options 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: https://localhost:/ + [webpack-dev-server] On Your Network (IPv4): https://:/ + [webpack-dev-server] On Your Network (IPv6): https://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + exports[`CLI https options 1`] = ` " [webpack-dev-server] Project is running at: [webpack-dev-server] Loopback: https://localhost:/ @@ -250,13 +258,13 @@ Options: --no-client-overlay Do not show a full-screen overlay in the browser when there are compiler errors or warnings. + --client-logging Log level in the browser (none, error, warn, + info, log, verbose). --open [value...] Open the default browser. --no-open Do not open the default browser. --open-app Open specified browser. --open-target [value...] Open specified route in browser. --no-open-target Do not open specified route in browser. - --client-logging Log level in the browser (none, error, warn, - info, log, verbose). --history-api-fallback Fallback to /index.html for Single Page Applications. --no-history-api-fallback Do not fallback to /index.html for Single diff --git a/test/cli/__snapshots__/cli.test.js.snap.webpack5 b/test/cli/__snapshots__/cli.test.js.snap.webpack5 index edceaa89e2..ffad849682 100644 --- a/test/cli/__snapshots__/cli.test.js.snap.webpack5 +++ b/test/cli/__snapshots__/cli.test.js.snap.webpack5 @@ -164,6 +164,14 @@ exports[`CLI --no-https-request-cert 1`] = ` [webpack-dev-server] Content not from webpack is served from '/public' directory" `; +exports[`CLI https and other related options 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: https://localhost:/ + [webpack-dev-server] On Your Network (IPv4): https://:/ + [webpack-dev-server] On Your Network (IPv6): https://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + exports[`CLI https options 1`] = ` " [webpack-dev-server] Project is running at: [webpack-dev-server] Loopback: https://localhost:/ @@ -251,13 +259,13 @@ Options: --no-client-overlay Do not show a full-screen overlay in the browser when there are compiler errors or warnings. + --client-logging Log level in the browser (none, error, warn, + info, log, verbose). --open [value...] Open the default browser. --no-open Do not open the default browser. --open-app Open specified browser. --open-target [value...] Open specified route in browser. --no-open-target Do not open specified route in browser. - --client-logging Log level in the browser (none, error, warn, - info, log, verbose). --history-api-fallback Fallback to /index.html for Single Page Applications. --no-history-api-fallback Do not fallback to /index.html for Single diff --git a/test/cli/cli.test.js b/test/cli/cli.test.js index 33cb600e08..f61b7eade1 100644 --- a/test/cli/cli.test.js +++ b/test/cli/cli.test.js @@ -209,6 +209,26 @@ describe('CLI', () => { .catch(done); }); + // For /~https://github.com/webpack/webpack-dev-server/issues/3306 + it('https and other related options', (done) => { + const pfxFile = path.join(httpsCertificateDirectory, 'server.pfx'); + const key = path.join(httpsCertificateDirectory, 'server.key'); + const cert = path.join(httpsCertificateDirectory, 'server.crt'); + const passphrase = 'webpack-dev-server'; + + testBin( + `--https --https-key ${key} --https-pfx ${pfxFile} --https-passphrase ${passphrase} --https-cert ${cert}` + ) + .then((output) => { + expect(output.exitCode).toEqual(0); + expect( + normalizeStderr(output.stderr, { ipv6: true, https: true }) + ).toMatchSnapshot(); + done(); + }) + .catch(done); + }); + it('--https-request-cert', (done) => { testBin('--https-request-cert') .then((output) => { @@ -484,6 +504,15 @@ describe('CLI', () => { .catch(done); }); + it(' --open --open-target index.html', (done) => { + testBin('--open --open-target index.html') + .then((output) => { + expect(output.exitCode).toEqual(0); + done(); + }) + .catch(done); + }); + it('--open-target /first.html second.html', (done) => { testBin('--open-target /first.html second.html') .then((output) => { @@ -502,6 +531,15 @@ describe('CLI', () => { .catch(done); }); + it('--open --open-target /index.html --open-app google-chrome', (done) => { + testBin('--open --open-target /index.html --open-app google-chrome') + .then((output) => { + expect(output.exitCode).toEqual(0); + done(); + }) + .catch(done); + }); + it('--client-overlay', (done) => { testBin('--client-overlay') .then((output) => { @@ -593,6 +631,20 @@ describe('CLI', () => { .catch(done); }); + it('--static --static-directory', (done) => { + testBin( + `--static --static-directory ${path.resolve( + __dirname, + '../fixtures/static/webpack.config.js' + )}` + ) + .then((output) => { + expect(output.exitCode).toEqual(0); + done(); + }) + .catch(done); + }); + it('--static-serve-index', (done) => { testBin('--static-serve-index') .then((output) => {