From 46aacfe4710346183f5867547e8111543825af6e Mon Sep 17 00:00:00 2001 From: John Chipps-Harding Date: Mon, 30 Sep 2019 22:52:14 +0100 Subject: [PATCH 1/5] feat: allow multiple openPage options as array --- lib/options.json | 15 ++- lib/utils/runOpen.js | 24 +++-- .../__snapshots__/createConfig.test.js.snap | 19 ++++ test/server/utils/createConfig.test.js | 15 +++ test/server/utils/runOpen.test.js | 102 ++++++++++++++++++ 5 files changed, 164 insertions(+), 11 deletions(-) diff --git a/lib/options.json b/lib/options.json index 217ee5a631..2842b7e30d 100644 --- a/lib/options.json +++ b/lib/options.json @@ -209,7 +209,18 @@ ] }, "openPage": { - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + } + ] }, "overlay": { "anyOf": [ @@ -436,7 +447,7 @@ "noInfo": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devservernoinfo-)", "onListening": "should be {Function} (https://webpack.js.org/configuration/dev-server/#onlistening)", "open": "should be {String|Boolean} (https://webpack.js.org/configuration/dev-server/#devserveropen)", - "openPage": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserveropenpage)", + "openPage": "should be {String|Array} (https://webpack.js.org/configuration/dev-server/#devserveropenpage)", "overlay": "should be {Boolean|Object} (https://webpack.js.org/configuration/dev-server/#devserveroverlay)", "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)", diff --git a/lib/utils/runOpen.js b/lib/utils/runOpen.js index a2757ab919..6609e91ca8 100644 --- a/lib/utils/runOpen.js +++ b/lib/utils/runOpen.js @@ -13,16 +13,22 @@ function runOpen(uri, options, log) { openMessage += `: ${options.open}`; } - const pageUrl = - options.openPage && isAbsoluteUrl(options.openPage) - ? options.openPage - : `${uri}${options.openPage || ''}`; + const pages = + typeof options.openPage === 'string' + ? [options.openPage] + : options.openPage || ['']; - return open(pageUrl, openOptions).catch(() => { - log.warn( - `${openMessage}. If you are running in a headless environment, please do not use the --open flag` - ); - }); + return Promise.all( + pages.map((page) => { + const pageUrl = page && isAbsoluteUrl(page) ? page : `${uri}${page}`; + + return open(pageUrl, openOptions).catch(() => { + log.warn( + `${openMessage}. If you are running in a headless environment, please do not use the --open flag` + ); + }); + }) + ); } module.exports = runOpen; diff --git a/test/server/utils/__snapshots__/createConfig.test.js.snap b/test/server/utils/__snapshots__/createConfig.test.js.snap index 585d74105c..d6f9dce0ea 100644 --- a/test/server/utils/__snapshots__/createConfig.test.js.snap +++ b/test/server/utils/__snapshots__/createConfig.test.js.snap @@ -818,6 +818,25 @@ Object { } `; +exports[`createConfig openPage multiple option (in devServer config) 1`] = ` +Object { + "hot": true, + "hotOnly": false, + "noInfo": true, + "open": true, + "openPage": Array [ + "/different/page", + "/different/page2", + ], + "port": 8080, + "publicPath": "/", + "stats": Object { + "cached": false, + "cachedAssets": false, + }, +} +`; + exports[`createConfig openPage option (in devServer config) 1`] = ` Object { "hot": true, diff --git a/test/server/utils/createConfig.test.js b/test/server/utils/createConfig.test.js index 685941ef56..746b7dba64 100644 --- a/test/server/utils/createConfig.test.js +++ b/test/server/utils/createConfig.test.js @@ -887,6 +887,21 @@ describe('createConfig', () => { expect(config).toMatchSnapshot(); }); + it('openPage multiple option (in devServer config)', () => { + const config = createConfig( + Object.assign({}, webpackConfig, { + devServer: { + open: true, + openPage: ['/different/page', '/different/page2'], + }, + }), + argv, + { port: 8080 } + ); + + expect(config).toMatchSnapshot(); + }); + it('useLocalIp option', () => { const config = createConfig( webpackConfig, diff --git a/test/server/utils/runOpen.test.js b/test/server/utils/runOpen.test.js index e6fa3b155a..8530a1a068 100644 --- a/test/server/utils/runOpen.test.js +++ b/test/server/utils/runOpen.test.js @@ -45,6 +45,48 @@ describe('runOpen util', () => { }); }); + it('on specify URL with page inside array', () => { + return runOpen( + 'https://example.com', + { openPage: ['/index.html'] }, + console + ).then(() => { + expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "https://example.com/index.html", + Object { + "wait": false, + }, + ] + `); + }); + }); + + it('on specify URL with multiple pages inside array', () => { + return runOpen( + 'https://example.com', + { openPage: ['/index.html', '/index2.html'] }, + console + ).then(() => { + expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "https://example.com/index.html", + Object { + "wait": false, + }, + ] + `); + expect(opn.mock.calls[1]).toMatchInlineSnapshot(` + Array [ + "https://example.com/index2.html", + Object { + "wait": false, + }, + ] + `); + }); + }); + it('on specify URL in Google Chrome', () => { return runOpen( 'https://example.com', @@ -118,6 +160,66 @@ describe('runOpen util', () => { }); }); + it('on specify multiple absolute https URLs with pages in Google Chrome ', () => { + return runOpen( + 'https://example.com', + { + open: 'Google Chrome', + openPage: ['https://example2.com', 'https://example3.com'], + }, + console + ).then(() => { + expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "https://example2.com", + Object { + "app": "Google Chrome", + "wait": false, + }, + ] + `); + expect(opn.mock.calls[1]).toMatchInlineSnapshot(` + Array [ + "https://example3.com", + Object { + "app": "Google Chrome", + "wait": false, + }, + ] + `); + }); + }); + + it('on specify one relative URL and one absolute URL with pages in Google Chrome ', () => { + return runOpen( + 'https://example.com', + { + open: 'Google Chrome', + openPage: ['/index.html', 'https://example2.com'], + }, + console + ).then(() => { + expect(opn.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "https://example.com/index.html", + Object { + "app": "Google Chrome", + "wait": false, + }, + ] + `); + expect(opn.mock.calls[1]).toMatchInlineSnapshot(` + Array [ + "https://example2.com", + Object { + "app": "Google Chrome", + "wait": false, + }, + ] + `); + }); + }); + describe('should not open browser', () => { const logMock = { warn: jest.fn() }; From aec9963a5ae0bd4bf337f88e89d7046ef04b2a66 Mon Sep 17 00:00:00 2001 From: John Chipps-Harding Date: Mon, 30 Sep 2019 23:33:48 +0100 Subject: [PATCH 2/5] feat: added open-page-multiple example --- examples/cli/open-page-multiple/README.md | 15 ++++++++ examples/cli/open-page-multiple/app1.js | 11 ++++++ examples/cli/open-page-multiple/app2.js | 11 ++++++ .../cli/open-page-multiple/webpack.config.js | 37 +++++++++++++++++++ examples/cli/open-page/README.md | 4 +- lib/utils/createConfig.js | 2 +- 6 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 examples/cli/open-page-multiple/README.md create mode 100644 examples/cli/open-page-multiple/app1.js create mode 100644 examples/cli/open-page-multiple/app2.js create mode 100644 examples/cli/open-page-multiple/webpack.config.js diff --git a/examples/cli/open-page-multiple/README.md b/examples/cli/open-page-multiple/README.md new file mode 100644 index 0000000000..e5d07ec496 --- /dev/null +++ b/examples/cli/open-page-multiple/README.md @@ -0,0 +1,15 @@ +# CLI: Open Page Option (Multiple) + +```console +npm run webpack-dev-server -- --open-page example1.html,example2.html +``` + +Some applications may consist of multiple pages. During development it may +be useful to directly open multiple pages at the same time. The pages to open +may be specified as the argument to the `open-page` option. + +## What Should Happen + +The script should open `http://localhost:8080/example1.html` and +`http://localhost:8080/example2.html` in your default browser. +You should see the text on the page itself change to read `Success!`. diff --git a/examples/cli/open-page-multiple/app1.js b/examples/cli/open-page-multiple/app1.js new file mode 100644 index 0000000000..45c49c5c7b --- /dev/null +++ b/examples/cli/open-page-multiple/app1.js @@ -0,0 +1,11 @@ +'use strict'; + +const target = document.querySelector('#target'); + +if (window.location.href.endsWith('example1.html')) { + target.classList.add('pass'); + target.innerHTML = 'Success!'; +} else { + target.classList.add('fail'); + target.innerHTML = 'Houston, we have a problem.'; +} diff --git a/examples/cli/open-page-multiple/app2.js b/examples/cli/open-page-multiple/app2.js new file mode 100644 index 0000000000..ca59bf8047 --- /dev/null +++ b/examples/cli/open-page-multiple/app2.js @@ -0,0 +1,11 @@ +'use strict'; + +const target = document.querySelector('#target'); + +if (window.location.href.endsWith('example2.html')) { + target.classList.add('pass'); + target.innerHTML = 'Success!'; +} else { + target.classList.add('fail'); + target.innerHTML = 'Houston, we have a problem.'; +} diff --git a/examples/cli/open-page-multiple/webpack.config.js b/examples/cli/open-page-multiple/webpack.config.js new file mode 100644 index 0000000000..d933139c04 --- /dev/null +++ b/examples/cli/open-page-multiple/webpack.config.js @@ -0,0 +1,37 @@ +'use strict'; + +const HtmlWebpackPlugin = require('html-webpack-plugin'); +// our setup function adds behind-the-scenes bits to the config that all of our +// examples need +const { setup } = require('../../util'); + +module.exports = [ + setup({ + context: __dirname, + entry: './app1.js', + output: { + filename: 'app1.js', + }, + plugins: [ + new HtmlWebpackPlugin({ + filename: 'example1.html', + template: '../../.assets/layout.html', + title: 'Open Page (Multiple) / Example / Page 1', + }), + ], + }), + setup({ + context: __dirname, + entry: './app2.js', + output: { + filename: 'app2.js', + }, + plugins: [ + new HtmlWebpackPlugin({ + filename: 'example2.html', + template: '../../.assets/layout.html', + title: 'Open Page (Multiple) / Example / Page 2', + }), + ], + }), +]; diff --git a/examples/cli/open-page/README.md b/examples/cli/open-page/README.md index f4c02f76cc..df88bfae78 100644 --- a/examples/cli/open-page/README.md +++ b/examples/cli/open-page/README.md @@ -10,5 +10,5 @@ as the argument to the `open-page` option. ## What Should Happen -The script should open `http://localhost:8080/` in your default browser. -You should see the text on the page itself change to read `Success!`. +The script should open `http://localhost:8080/example.html#page1` in your +default browser. You should see the text on the page itself change to read `Success!`. diff --git a/lib/utils/createConfig.js b/lib/utils/createConfig.js index 0211561235..5c15b35c39 100644 --- a/lib/utils/createConfig.js +++ b/lib/utils/createConfig.js @@ -203,7 +203,7 @@ function createConfig(config, argv, { port }) { if (argv.openPage) { options.open = true; - options.openPage = argv.openPage; + options.openPage = argv.openPage.split(','); } if (typeof argv.open !== 'undefined') { From c72799449fe3552b5c60195c0b17d04dc4193070 Mon Sep 17 00:00:00 2001 From: John Chipps-Harding Date: Tue, 1 Oct 2019 00:25:44 +0100 Subject: [PATCH 3/5] test: moved to standard snapshots --- .../__snapshots__/createConfig.test.js.snap | 4 +- .../utils/__snapshots__/runOpen.test.js.snap | 68 +++++++++++++++++++ test/server/utils/runOpen.test.js | 67 ++---------------- 3 files changed, 78 insertions(+), 61 deletions(-) create mode 100644 test/server/utils/__snapshots__/runOpen.test.js.snap diff --git a/test/server/utils/__snapshots__/createConfig.test.js.snap b/test/server/utils/__snapshots__/createConfig.test.js.snap index d6f9dce0ea..dd2215151b 100644 --- a/test/server/utils/__snapshots__/createConfig.test.js.snap +++ b/test/server/utils/__snapshots__/createConfig.test.js.snap @@ -859,7 +859,9 @@ Object { "hotOnly": false, "noInfo": true, "open": true, - "openPage": "/different/page", + "openPage": Array [ + "/different/page", + ], "port": 8080, "publicPath": "/", "stats": Object { diff --git a/test/server/utils/__snapshots__/runOpen.test.js.snap b/test/server/utils/__snapshots__/runOpen.test.js.snap new file mode 100644 index 0000000000..af9cecdd6f --- /dev/null +++ b/test/server/utils/__snapshots__/runOpen.test.js.snap @@ -0,0 +1,68 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`runOpen util on specify multiple absolute https URLs with pages in Google Chrome 1`] = ` +Array [ + "https://example2.com", + Object { + "app": "Google Chrome", + "wait": false, + }, +] +`; + +exports[`runOpen util on specify multiple absolute https URLs with pages in Google Chrome 2`] = ` +Array [ + "https://example3.com", + Object { + "app": "Google Chrome", + "wait": false, + }, +] +`; + +exports[`runOpen util on specify one relative URL and one absolute URL with pages in Google Chrome 1`] = ` +Array [ + "https://example.com/index.html", + Object { + "app": "Google Chrome", + "wait": false, + }, +] +`; + +exports[`runOpen util on specify one relative URL and one absolute URL with pages in Google Chrome 2`] = ` +Array [ + "https://example2.com", + Object { + "app": "Google Chrome", + "wait": false, + }, +] +`; + +exports[`runOpen util should open browser on specify URL with multiple pages inside array 1`] = ` +Array [ + "https://example.com/index.html", + Object { + "wait": false, + }, +] +`; + +exports[`runOpen util should open browser on specify URL with multiple pages inside array 2`] = ` +Array [ + "https://example.com/index2.html", + Object { + "wait": false, + }, +] +`; + +exports[`runOpen util should open browser on specify URL with page inside array 1`] = ` +Array [ + "https://example.com/index.html", + Object { + "wait": false, + }, +] +`; diff --git a/test/server/utils/runOpen.test.js b/test/server/utils/runOpen.test.js index 8530a1a068..795f1c1201 100644 --- a/test/server/utils/runOpen.test.js +++ b/test/server/utils/runOpen.test.js @@ -51,14 +51,7 @@ describe('runOpen util', () => { { openPage: ['/index.html'] }, console ).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "https://example.com/index.html", - Object { - "wait": false, - }, - ] - `); + expect(opn.mock.calls[0]).toMatchSnapshot(); }); }); @@ -68,22 +61,8 @@ describe('runOpen util', () => { { openPage: ['/index.html', '/index2.html'] }, console ).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "https://example.com/index.html", - Object { - "wait": false, - }, - ] - `); - expect(opn.mock.calls[1]).toMatchInlineSnapshot(` - Array [ - "https://example.com/index2.html", - Object { - "wait": false, - }, - ] - `); + expect(opn.mock.calls[0]).toMatchSnapshot(); + expect(opn.mock.calls[1]).toMatchSnapshot(); }); }); @@ -169,24 +148,8 @@ describe('runOpen util', () => { }, console ).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "https://example2.com", - Object { - "app": "Google Chrome", - "wait": false, - }, - ] - `); - expect(opn.mock.calls[1]).toMatchInlineSnapshot(` - Array [ - "https://example3.com", - Object { - "app": "Google Chrome", - "wait": false, - }, - ] - `); + expect(opn.mock.calls[0]).toMatchSnapshot(); + expect(opn.mock.calls[1]).toMatchSnapshot(); }); }); @@ -199,24 +162,8 @@ describe('runOpen util', () => { }, console ).then(() => { - expect(opn.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "https://example.com/index.html", - Object { - "app": "Google Chrome", - "wait": false, - }, - ] - `); - expect(opn.mock.calls[1]).toMatchInlineSnapshot(` - Array [ - "https://example2.com", - Object { - "app": "Google Chrome", - "wait": false, - }, - ] - `); + expect(opn.mock.calls[0]).toMatchSnapshot(); + expect(opn.mock.calls[1]).toMatchSnapshot(); }); }); From df0384ee42f41dcb699f222bdc080b44e0f12e09 Mon Sep 17 00:00:00 2001 From: John Chipps-Harding Date: Wed, 2 Oct 2019 03:23:31 +0100 Subject: [PATCH 4/5] fix: runOpen - made warning output related url --- lib/utils/runOpen.js | 6 +++--- test/server/utils/runOpen.test.js | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/utils/runOpen.js b/lib/utils/runOpen.js index 6609e91ca8..ea2a3c8d46 100644 --- a/lib/utils/runOpen.js +++ b/lib/utils/runOpen.js @@ -6,11 +6,11 @@ const isAbsoluteUrl = require('is-absolute-url'); function runOpen(uri, options, log) { // https://github.com/webpack/webpack-dev-server/issues/1990 let openOptions = { wait: false }; - let openMessage = 'Unable to open browser'; + let openOptionValue = ''; if (typeof options.open === 'string') { openOptions = Object.assign({}, openOptions, { app: options.open }); - openMessage += `: ${options.open}`; + openOptionValue = `: ${options.open}`; } const pages = @@ -24,7 +24,7 @@ function runOpen(uri, options, log) { return open(pageUrl, openOptions).catch(() => { log.warn( - `${openMessage}. If you are running in a headless environment, please do not use the --open flag` + `Unable to open ${pageUrl} in browser${openOptionValue}. If you are running in a headless environment, please do not use the --open flag` ); }); }) diff --git a/test/server/utils/runOpen.test.js b/test/server/utils/runOpen.test.js index 795f1c1201..130e364d6a 100644 --- a/test/server/utils/runOpen.test.js +++ b/test/server/utils/runOpen.test.js @@ -181,7 +181,7 @@ describe('runOpen util', () => { it('on specify URL and log error', () => { return runOpen('https://example.com', {}, logMock).then(() => { expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open browser. If you are running in a headless environment, please do not use the --open flag"` + `"Unable to open https://example.com in browser. If you are running in a headless environment, please do not use the --open flag"` ); expect(opn.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -201,7 +201,7 @@ describe('runOpen util', () => { logMock ).then(() => { expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open browser. If you are running in a headless environment, please do not use the --open flag"` + `"Unable to open https://example.com/index.html in browser. If you are running in a headless environment, please do not use the --open flag"` ); expect(opn.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -221,7 +221,7 @@ describe('runOpen util', () => { logMock ).then(() => { expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` + `"Unable to open https://example.com in browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` ); expect(opn.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -242,7 +242,7 @@ describe('runOpen util', () => { logMock ).then(() => { expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` + `"Unable to open https://example.com/index.html in browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` ); expect(opn.mock.calls[0]).toMatchInlineSnapshot(` Array [ From b2907b8863d85f8e3800ce133069674d51a53ccb Mon Sep 17 00:00:00 2001 From: John Chipps-Harding Date: Wed, 2 Oct 2019 17:48:29 +0100 Subject: [PATCH 5/5] fix: added quotes around path and browser --- lib/utils/runOpen.js | 4 ++-- test/server/utils/runOpen.test.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/utils/runOpen.js b/lib/utils/runOpen.js index ea2a3c8d46..0b42eff54d 100644 --- a/lib/utils/runOpen.js +++ b/lib/utils/runOpen.js @@ -10,7 +10,7 @@ function runOpen(uri, options, log) { if (typeof options.open === 'string') { openOptions = Object.assign({}, openOptions, { app: options.open }); - openOptionValue = `: ${options.open}`; + openOptionValue = `: "${options.open}"`; } const pages = @@ -24,7 +24,7 @@ function runOpen(uri, options, log) { return open(pageUrl, openOptions).catch(() => { log.warn( - `Unable to open ${pageUrl} in browser${openOptionValue}. If you are running in a headless environment, please do not use the --open flag` + `Unable to open "${pageUrl}" in browser${openOptionValue}. If you are running in a headless environment, please do not use the --open flag` ); }); }) diff --git a/test/server/utils/runOpen.test.js b/test/server/utils/runOpen.test.js index 130e364d6a..80fe358512 100644 --- a/test/server/utils/runOpen.test.js +++ b/test/server/utils/runOpen.test.js @@ -181,7 +181,7 @@ describe('runOpen util', () => { it('on specify URL and log error', () => { return runOpen('https://example.com', {}, logMock).then(() => { expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open https://example.com in browser. If you are running in a headless environment, please do not use the --open flag"` + `"Unable to open \\"https://example.com\\" in browser. If you are running in a headless environment, please do not use the --open flag"` ); expect(opn.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -201,7 +201,7 @@ describe('runOpen util', () => { logMock ).then(() => { expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open https://example.com/index.html in browser. If you are running in a headless environment, please do not use the --open flag"` + `"Unable to open \\"https://example.com/index.html\\" in browser. If you are running in a headless environment, please do not use the --open flag"` ); expect(opn.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -221,7 +221,7 @@ describe('runOpen util', () => { logMock ).then(() => { expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open https://example.com in browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` + `"Unable to open \\"https://example.com\\" in browser: \\"Google Chrome\\". If you are running in a headless environment, please do not use the --open flag"` ); expect(opn.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -242,7 +242,7 @@ describe('runOpen util', () => { logMock ).then(() => { expect(logMock.warn.mock.calls[0][0]).toMatchInlineSnapshot( - `"Unable to open https://example.com/index.html in browser: Google Chrome. If you are running in a headless environment, please do not use the --open flag"` + `"Unable to open \\"https://example.com/index.html\\" in browser: \\"Google Chrome\\". If you are running in a headless environment, please do not use the --open flag"` ); expect(opn.mock.calls[0]).toMatchInlineSnapshot(` Array [