From dc87d8bddd3be01549ff5f099ff87500babad1fd Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sun, 6 Jun 2021 08:11:59 +0530 Subject: [PATCH 01/12] refactor: move `runBonjour` to `Server` --- lib/Server.js | 24 +++++++++++++++++++++--- lib/utils/runBonjour.js | 22 ---------------------- 2 files changed, 21 insertions(+), 25 deletions(-) delete mode 100644 lib/utils/runBonjour.js diff --git a/lib/Server.js b/lib/Server.js index b13b184274..415791d9f6 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -539,6 +539,26 @@ class Server { }); } + static runBonjour(options) { + const bonjour = require('bonjour')(); + const os = require('os'); + const { https, port } = options; + + bonjour.publish({ + name: `Webpack Dev Server ${os.hostname()}:${port}`, + port, + type: https ? 'https' : 'http', + subtypes: ['webpack'], + ...options.bonjour, + }); + + process.on('exit', () => { + bonjour.unpublishAll(() => { + bonjour.destroy(); + }); + }); + } + logStatus() { const useColor = getColorsOption(getCompilerConfigArray(this.compiler)); const protocol = this.options.https ? 'https' : 'http'; @@ -724,9 +744,7 @@ class Server { } if (this.options.bonjour) { - const runBonjour = require('./utils/runBonjour'); - - runBonjour(this.options); + Server.runBonjour(this.options); } this.logStatus(); diff --git a/lib/utils/runBonjour.js b/lib/utils/runBonjour.js deleted file mode 100644 index 825c15af81..0000000000 --- a/lib/utils/runBonjour.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -function runBonjour(options) { - const bonjour = require('bonjour')(); - const os = require('os'); - const { https, port } = options; - bonjour.publish({ - name: `Webpack Dev Server ${os.hostname()}:${port}`, - port, - type: https ? 'https' : 'http', - subtypes: ['webpack'], - ...options.bonjour, - }); - - process.on('exit', () => { - bonjour.unpublishAll(() => { - bonjour.destroy(); - }); - }); -} - -module.exports = runBonjour; From 24cabe838f4e71276edc986963557021b1f34e61 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sun, 6 Jun 2021 08:22:52 +0530 Subject: [PATCH 02/12] refactor: inline `runOpen` util --- lib/Server.js | 88 ++++++++++++++++++++++++++++++++++++++++++-- lib/utils/runOpen.js | 87 ------------------------------------------- 2 files changed, 85 insertions(+), 90 deletions(-) delete mode 100644 lib/utils/runOpen.js diff --git a/lib/Server.js b/lib/Server.js index 415791d9f6..d45236ffda 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -559,6 +559,90 @@ class Server { }); } + static runOpen(uri, options, logger) { + const isAbsoluteUrl = require('is-absolute-url'); + const open = require('open'); + + // https://github.com/webpack/webpack-dev-server/issues/1990 + const defaultOpenOptions = { wait: false }; + const openTasks = []; + + const getOpenTask = (item) => { + if (typeof item === 'boolean') { + return [{ target: uri, options: defaultOpenOptions }]; + } + + if (typeof item === 'string') { + return [{ target: item, options: defaultOpenOptions }]; + } + + let targets; + + if (item.target) { + targets = Array.isArray(item.target) ? item.target : [item.target]; + } else { + targets = [uri]; + } + + return targets.map((target) => { + const openOptions = defaultOpenOptions; + + if (item.app) { + if (typeof item.app === 'string') { + openOptions.app = { name: item.app }; + } else { + openOptions.app = item.app; + } + } + + return { target, options: openOptions }; + }); + }; + + if (Array.isArray(options)) { + options.forEach((item) => { + openTasks.push(...getOpenTask(item)); + }); + } else { + openTasks.push(...getOpenTask(options)); + } + + return Promise.all( + openTasks.map((openTask) => { + let openTarget; + + if (openTask.target) { + if (typeof openTask.target === 'boolean') { + openTarget = uri; + } else { + openTarget = isAbsoluteUrl(openTask.target) + ? openTask.target + : new URL(openTask.target, uri).toString(); + } + } else { + openTarget = uri; + } + + return open(openTarget, openTask.options).catch(() => { + logger.warn( + `Unable to open "${openTarget}" page${ + // eslint-disable-next-line no-nested-ternary + openTask.options.app + ? ` in "${openTask.options.app.name}" app${ + openTask.options.app.arguments + ? ` with "${openTask.options.app.arguments.join( + ' ' + )}" arguments` + : '' + }` + : '' + }. If you are running in a headless environment, please do not use the "open" option or related flags like "--open", "--open-target", and "--open-app".` + ); + }); + }) + ); + } + logStatus() { const useColor = getColorsOption(getCompilerConfigArray(this.compiler)); const protocol = this.options.https ? 'https' : 'http'; @@ -681,11 +765,9 @@ class Server { } if (this.options.open) { - const runOpen = require('./utils/runOpen'); - const openTarget = prettyPrintUrl(this.options.host || 'localhost'); - runOpen(openTarget, this.options.open, this.logger); + Server.runOpen(openTarget, this.options.open, this.logger); } } diff --git a/lib/utils/runOpen.js b/lib/utils/runOpen.js deleted file mode 100644 index 8e1660d3cb..0000000000 --- a/lib/utils/runOpen.js +++ /dev/null @@ -1,87 +0,0 @@ -'use strict'; - -const open = require('open'); -const isAbsoluteUrl = require('is-absolute-url'); - -function runOpen(uri, options, logger) { - // https://github.com/webpack/webpack-dev-server/issues/1990 - const defaultOpenOptions = { wait: false }; - const openTasks = []; - - const getOpenTask = (item) => { - if (typeof item === 'boolean') { - return [{ target: uri, options: defaultOpenOptions }]; - } - - if (typeof item === 'string') { - return [{ target: item, options: defaultOpenOptions }]; - } - - let targets; - - if (item.target) { - targets = Array.isArray(item.target) ? item.target : [item.target]; - } else { - targets = [uri]; - } - - return targets.map((target) => { - const openOptions = defaultOpenOptions; - - if (item.app) { - if (typeof item.app === 'string') { - openOptions.app = { name: item.app }; - } else { - openOptions.app = item.app; - } - } - - return { target, options: openOptions }; - }); - }; - - if (Array.isArray(options)) { - options.forEach((item) => { - openTasks.push(...getOpenTask(item)); - }); - } else { - openTasks.push(...getOpenTask(options)); - } - - return Promise.all( - openTasks.map((openTask) => { - let openTarget; - - if (openTask.target) { - if (typeof openTask.target === 'boolean') { - openTarget = uri; - } else { - openTarget = isAbsoluteUrl(openTask.target) - ? openTask.target - : new URL(openTask.target, uri).toString(); - } - } else { - openTarget = uri; - } - - return open(openTarget, openTask.options).catch(() => { - logger.warn( - `Unable to open "${openTarget}" page${ - // eslint-disable-next-line no-nested-ternary - openTask.options.app - ? ` in "${openTask.options.app.name}" app${ - openTask.options.app.arguments - ? ` with "${openTask.options.app.arguments.join( - ' ' - )}" arguments` - : '' - }` - : '' - }. If you are running in a headless environment, please do not use the "open" option or related flags like "--open", "--open-target", and "--open-app".` - ); - }); - }) - ); -} - -module.exports = runOpen; From 013780034261f6ea387766b83b7baeab2546f608 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Sun, 6 Jun 2021 08:28:27 +0530 Subject: [PATCH 03/12] refactor: code --- lib/Server.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Server.js b/lib/Server.js index d45236ffda..2ee638faf4 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -559,7 +559,7 @@ class Server { }); } - static runOpen(uri, options, logger) { + runOpen(uri, options) { const isAbsoluteUrl = require('is-absolute-url'); const open = require('open'); @@ -624,7 +624,7 @@ class Server { } return open(openTarget, openTask.options).catch(() => { - logger.warn( + this.logger.warn( `Unable to open "${openTarget}" page${ // eslint-disable-next-line no-nested-ternary openTask.options.app @@ -767,7 +767,7 @@ class Server { if (this.options.open) { const openTarget = prettyPrintUrl(this.options.host || 'localhost'); - Server.runOpen(openTarget, this.options.open, this.logger); + this.runOpen(openTarget, this.options.open); } } From 4157ef1037b50729cdb63804013e8893f887d9c3 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Mon, 7 Jun 2021 16:40:51 +0530 Subject: [PATCH 04/12] refactor: code --- lib/Server.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Server.js b/lib/Server.js index 2ee638faf4..55c602ea73 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -539,7 +539,7 @@ class Server { }); } - static runBonjour(options) { + runBonjour(options) { const bonjour = require('bonjour')(); const os = require('os'); const { https, port } = options; @@ -559,7 +559,7 @@ class Server { }); } - runOpen(uri, options) { + openBrowser(uri, options) { const isAbsoluteUrl = require('is-absolute-url'); const open = require('open'); @@ -767,7 +767,7 @@ class Server { if (this.options.open) { const openTarget = prettyPrintUrl(this.options.host || 'localhost'); - this.runOpen(openTarget, this.options.open); + this.openBrowser(openTarget, this.options.open); } } @@ -826,7 +826,7 @@ class Server { } if (this.options.bonjour) { - Server.runBonjour(this.options); + this.runBonjour(this.options); } this.logStatus(); From 0376be7158c100d46321826786cab5b7a40aa018 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Mon, 7 Jun 2021 16:49:47 +0530 Subject: [PATCH 05/12] refactor: code --- lib/Server.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Server.js b/lib/Server.js index 55c602ea73..ce6d08d1f8 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -539,17 +539,17 @@ class Server { }); } - runBonjour(options) { + runBonjour() { const bonjour = require('bonjour')(); const os = require('os'); - const { https, port } = options; + const { https, port } = this.options; bonjour.publish({ name: `Webpack Dev Server ${os.hostname()}:${port}`, port, type: https ? 'https' : 'http', subtypes: ['webpack'], - ...options.bonjour, + ...this.options.bonjour, }); process.on('exit', () => { @@ -607,7 +607,7 @@ class Server { openTasks.push(...getOpenTask(options)); } - return Promise.all( + Promise.all( openTasks.map((openTask) => { let openTarget; @@ -826,7 +826,7 @@ class Server { } if (this.options.bonjour) { - this.runBonjour(this.options); + this.runBonjour(); } this.logStatus(); From 4fb7bdc13de00deba2570859c5f515d35ee62eff Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Tue, 15 Jun 2021 14:43:28 +0530 Subject: [PATCH 06/12] refactor: code --- lib/Server.js | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/lib/Server.js b/lib/Server.js index ce6d08d1f8..a287cff9e8 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -539,26 +539,6 @@ class Server { }); } - runBonjour() { - const bonjour = require('bonjour')(); - const os = require('os'); - const { https, port } = this.options; - - bonjour.publish({ - name: `Webpack Dev Server ${os.hostname()}:${port}`, - port, - type: https ? 'https' : 'http', - subtypes: ['webpack'], - ...this.options.bonjour, - }); - - process.on('exit', () => { - bonjour.unpublishAll(() => { - bonjour.destroy(); - }); - }); - } - openBrowser(uri, options) { const isAbsoluteUrl = require('is-absolute-url'); const open = require('open'); @@ -826,7 +806,23 @@ class Server { } if (this.options.bonjour) { - this.runBonjour(); + const bonjour = require('bonjour')(); + const os = require('os'); + const { https, port } = this.options; + + bonjour.publish({ + name: `Webpack Dev Server ${os.hostname()}:${port}`, + port, + type: https ? 'https' : 'http', + subtypes: ['webpack'], + ...this.options.bonjour, + }); + + process.on('exit', () => { + bonjour.unpublishAll(() => { + bonjour.destroy(); + }); + }); } this.logStatus(); From 3441863a9f1a74e649dbd7af7491ba37c90ddd28 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Mon, 21 Jun 2021 15:27:45 +0300 Subject: [PATCH 07/12] refactor: more --- lib/Server.js | 163 ++++++++++++++++++++++-------------- lib/utils/findCacheDir.js | 32 ------- lib/utils/getCertificate.js | 4 +- 3 files changed, 102 insertions(+), 97 deletions(-) delete mode 100644 lib/utils/findCacheDir.js diff --git a/lib/Server.js b/lib/Server.js index a287cff9e8..2fad98ef8f 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -1,5 +1,7 @@ 'use strict'; +const path = require('path'); +const fs = require('fs'); const url = require('url'); const ipaddr = require('ipaddr.js'); const internalIp = require('internal-ip'); @@ -74,6 +76,79 @@ class Server { }, this); } + static get DEFAULT_STATS() { + return { + all: false, + hash: true, + assets: true, + warnings: true, + errors: true, + errorDetails: false, + }; + } + + static getFreePort(port) { + const pRetry = require('p-retry'); + const portfinder = require('portfinder'); + + if (port && port !== 'auto') { + return Promise.resolve(port); + } + + function runPortFinder() { + return new Promise((resolve, reject) => { + // default port + portfinder.basePort = 8080; + portfinder.getPort((error, foundPort) => { + if (error) { + return reject(error); + } + + return resolve(foundPort); + }); + }); + } + + // Try to find unused port and listen on it for 3 times, + // if port is not specified in options. + const defaultPortRetry = parseInt(process.env.DEFAULT_PORT_RETRY, 10) || 3; + + return pRetry(runPortFinder, { retries: defaultPortRetry }); + } + + static findCacheDir() { + const cwd = process.cwd(); + + let dir = cwd; + + for (;;) { + try { + if (fs.statSync(path.join(dir, 'package.json')).isFile()) break; + // eslint-disable-next-line no-empty + } catch (e) {} + + const parent = path.dirname(dir); + + if (dir === parent) { + // eslint-disable-next-line no-undefined + dir = undefined; + break; + } + + dir = parent; + } + + if (!dir) { + return path.resolve(cwd, '.cache/webpack-dev-server'); + } else if (process.versions.pnp === '1') { + return path.resolve(dir, '.pnp/.cache/webpack-dev-server'); + } else if (process.versions.pnp === '3') { + return path.resolve(dir, '.yarn/.cache/webpack-dev-server'); + } + + return path.resolve(dir, 'node_modules/.cache/webpack-dev-server'); + } + applyDevServerPlugin() { const DevServerPlugin = require('./utils/DevServerPlugin'); @@ -539,7 +614,7 @@ class Server { }); } - openBrowser(uri, options) { + openBrowser(uri) { const isAbsoluteUrl = require('is-absolute-url'); const open = require('open'); @@ -579,12 +654,12 @@ class Server { }); }; - if (Array.isArray(options)) { - options.forEach((item) => { + if (Array.isArray(this.options.open)) { + this.options.open.forEach((item) => { openTasks.push(...getOpenTask(item)); }); } else { - openTasks.push(...getOpenTask(options)); + openTasks.push(...getOpenTask(this.options.open)); } Promise.all( @@ -623,6 +698,25 @@ class Server { ); } + runBonjour() { + const bonjour = require('bonjour')(); + const os = require('os'); + + bonjour.publish({ + name: `Webpack Dev Server ${os.hostname()}:${this.options.port}`, + port: this.options.port, + type: this.options.https ? 'https' : 'http', + subtypes: ['webpack'], + ...this.options.bonjour, + }); + + process.on('exit', () => { + bonjour.unpublishAll(() => { + bonjour.destroy(); + }); + }); + } + logStatus() { const useColor = getColorsOption(getCompilerConfigArray(this.compiler)); const protocol = this.options.https ? 'https' : 'http'; @@ -747,7 +841,7 @@ class Server { if (this.options.open) { const openTarget = prettyPrintUrl(this.options.host || 'localhost'); - this.openBrowser(openTarget, this.options.open); + this.openBrowser(openTarget); } } @@ -806,23 +900,7 @@ class Server { } if (this.options.bonjour) { - const bonjour = require('bonjour')(); - const os = require('os'); - const { https, port } = this.options; - - bonjour.publish({ - name: `Webpack Dev Server ${os.hostname()}:${port}`, - port, - type: https ? 'https' : 'http', - subtypes: ['webpack'], - ...this.options.bonjour, - }); - - process.on('exit', () => { - bonjour.unpublishAll(() => { - bonjour.destroy(); - }); - }); + this.runBonjour(); } this.logStatus(); @@ -863,47 +941,6 @@ class Server { }); } - static get DEFAULT_STATS() { - return { - all: false, - hash: true, - assets: true, - warnings: true, - errors: true, - errorDetails: false, - }; - } - - static getFreePort(port) { - const pRetry = require('p-retry'); - const portfinder = require('portfinder'); - - if (port && port !== 'auto') { - return Promise.resolve(port); - } - - function runPortFinder() { - return new Promise((resolve, reject) => { - // default port - portfinder.basePort = process.env.WEBPACK_DEV_SERVER_BASE_PORT || 8080; - portfinder.getPort((error, foundPort) => { - if (error) { - return reject(error); - } - - return resolve(foundPort); - }); - }); - } - - // Try to find unused port and listen on it for 3 times, - // if port is not specified in options. - const defaultPortRetry = - parseInt(process.env.WEBPACK_DEV_SERVER_PORT_RETRY, 10) || 3; - - return pRetry(runPortFinder, { retries: defaultPortRetry }); - } - getStats(statsObj) { const stats = Server.DEFAULT_STATS; diff --git a/lib/utils/findCacheDir.js b/lib/utils/findCacheDir.js deleted file mode 100644 index 512fdcb3ee..0000000000 --- a/lib/utils/findCacheDir.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); - -const findCacheDir = () => { - const cwd = process.cwd(); - let dir = cwd; - for (;;) { - try { - if (fs.statSync(path.join(dir, 'package.json')).isFile()) break; - // eslint-disable-next-line no-empty - } catch (e) {} - const parent = path.dirname(dir); - if (dir === parent) { - // eslint-disable-next-line no-undefined - dir = undefined; - break; - } - dir = parent; - } - if (!dir) { - return path.resolve(cwd, '.cache/webpack-dev-server'); - } else if (process.versions.pnp === '1') { - return path.resolve(dir, '.pnp/.cache/webpack-dev-server'); - } else if (process.versions.pnp === '3') { - return path.resolve(dir, '.yarn/.cache/webpack-dev-server'); - } - return path.resolve(dir, 'node_modules/.cache/webpack-dev-server'); -}; - -module.exports = findCacheDir; diff --git a/lib/utils/getCertificate.js b/lib/utils/getCertificate.js index 3facb5cc8f..7179979c19 100644 --- a/lib/utils/getCertificate.js +++ b/lib/utils/getCertificate.js @@ -4,14 +4,14 @@ const path = require('path'); const os = require('os'); const fs = require('graceful-fs'); const del = require('del'); -const findCacheDir = require('./findCacheDir'); +const Server = require('../Server'); const createCertificate = require('./createCertificate'); function getCertificate(logger) { // Use a self-signed certificate if no certificate was configured. // Cycle certs every 24 hours const certificateDir = - findCacheDir({ name: 'webpack-dev-server' }) || os.tmpdir(); + Server.findCacheDir({ name: 'webpack-dev-server' }) || os.tmpdir(); const certificatePath = path.join(certificateDir, 'server.pem'); let certificateExists = fs.existsSync(certificatePath); From 59e69803e29209ad37287bf2a161d0e504056ce0 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Mon, 21 Jun 2021 15:33:07 +0300 Subject: [PATCH 08/12] refactor: more --- lib/Server.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/Server.js b/lib/Server.js index 2fad98ef8f..4853906680 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -87,6 +87,18 @@ class Server { }; } + static getHostname(hostname) { + if (hostname === 'local-ip') { + return internalIp.v4.sync() || internalIp.v6.sync() || '0.0.0.0'; + } else if (hostname === 'local-ipv4') { + return internalIp.v4.sync() || '0.0.0.0'; + } else if (hostname === 'local-ipv6') { + return internalIp.v6.sync() || '::'; + } + + return hostname; + } + static getFreePort(port) { const pRetry = require('p-retry'); const portfinder = require('portfinder'); @@ -878,14 +890,7 @@ class Server { this.options.host = hostname; } - if (this.options.host === 'local-ip') { - this.options.host = - internalIp.v4.sync() || internalIp.v6.sync() || '0.0.0.0'; - } else if (this.options.host === 'local-ipv4') { - this.options.host = internalIp.v4.sync() || '0.0.0.0'; - } else if (this.options.host === 'local-ipv6') { - this.options.host = internalIp.v6.sync() || '::'; - } + this.options.host = Server.getHostname(this.options.host); return Server.getFreePort(this.options.port) .then((foundPort) => { From 6406a085adb3750053d396e73d2c96fd5567dfd9 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Mon, 21 Jun 2021 15:36:12 +0300 Subject: [PATCH 09/12] refactor: more --- lib/Server.js | 13 ++++++++++++- lib/utils/getColorsOption.js | 15 --------------- 2 files changed, 12 insertions(+), 16 deletions(-) delete mode 100644 lib/utils/getColorsOption.js diff --git a/lib/Server.js b/lib/Server.js index 4853906680..5ec2dec00a 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -15,7 +15,6 @@ const getSocketServerImplementation = require('./utils/getSocketServerImplementa const getCompilerConfigArray = require('./utils/getCompilerConfigArray'); const setupExitSignals = require('./utils/setupExitSignals'); const getStatsOption = require('./utils/getStatsOption'); -const getColorsOption = require('./utils/getColorsOption'); const schema = require('./options.json'); if (!process.env.WEBPACK_SERVE) { @@ -730,6 +729,18 @@ class Server { } logStatus() { + const getColorsOption = (configArray) => { + const statsOption = getStatsOption(configArray); + + let colorsEnabled = false; + + if (typeof statsOption === 'object' && statsOption.colors) { + colorsEnabled = statsOption.colors; + } + + return colorsEnabled; + }; + const useColor = getColorsOption(getCompilerConfigArray(this.compiler)); const protocol = this.options.https ? 'https' : 'http'; const { address, port } = this.server.address(); diff --git a/lib/utils/getColorsOption.js b/lib/utils/getColorsOption.js deleted file mode 100644 index 75667b49dc..0000000000 --- a/lib/utils/getColorsOption.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -const getStatsOption = require('./getStatsOption'); - -function getColorsOption(configArr) { - const statsOption = getStatsOption(configArr); - let colors = false; - if (typeof statsOption === 'object' && statsOption.colors) { - colors = statsOption.colors; - } - - return colors; -} - -module.exports = getColorsOption; From bf5321b09b60b75704dffd90aee2395ba86ea0eb Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Mon, 21 Jun 2021 15:40:48 +0300 Subject: [PATCH 10/12] refactor: more --- lib/Server.js | 15 +++++++++++++-- lib/utils/setupExitSignals.js | 25 ------------------------- 2 files changed, 13 insertions(+), 27 deletions(-) delete mode 100644 lib/utils/setupExitSignals.js diff --git a/lib/Server.js b/lib/Server.js index 5ec2dec00a..7081926f0f 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -13,7 +13,6 @@ const colors = require('./utils/colors'); const routes = require('./utils/routes'); const getSocketServerImplementation = require('./utils/getSocketServerImplementation'); const getCompilerConfigArray = require('./utils/getCompilerConfigArray'); -const setupExitSignals = require('./utils/setupExitSignals'); const getStatsOption = require('./utils/getStatsOption'); const schema = require('./options.json'); @@ -65,7 +64,19 @@ class Server { this.createServer(); killable(this.server); - setupExitSignals(this); + + if (this.options.setupExitSignals) { + const signals = ['SIGINT', 'SIGTERM']; + + signals.forEach((signal) => { + process.on(signal, () => { + this.close(() => { + // eslint-disable-next-line no-process-exit + process.exit(); + }); + }); + }); + } // Proxy WebSocket without the initial http request // https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade diff --git a/lib/utils/setupExitSignals.js b/lib/utils/setupExitSignals.js deleted file mode 100644 index 2ad59ea589..0000000000 --- a/lib/utils/setupExitSignals.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -const signals = ['SIGINT', 'SIGTERM']; - -function setupExitSignals(server) { - const closeAndExit = () => { - if (server) { - server.close(() => { - // eslint-disable-next-line no-process-exit - process.exit(); - }); - } else { - // eslint-disable-next-line no-process-exit - process.exit(); - } - }; - - if (server.options.setupExitSignals) { - signals.forEach((signal) => { - process.on(signal, closeAndExit); - }); - } -} - -module.exports = setupExitSignals; From a5c3ec8aaa631424cd530d563584889907dff3d5 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Mon, 21 Jun 2021 16:41:28 +0300 Subject: [PATCH 11/12] refactor: more --- lib/Server.js | 7 +- lib/utils/createCertificate.js | 69 ----------- lib/utils/getCertificate.js | 50 -------- lib/utils/normalizeOptions.js | 108 ++++++++++++++++-- .../colors.test.js.snap.webpack4 | 41 +++++++ .../colors.test.js.snap.webpack5 | 41 +++++++ test/cli/colors.test.js | 58 ++++++++++ test/fixtures/cli-colors-default-stats/foo.js | 3 + .../webpack.config.js | 10 ++ test/fixtures/cli-colors-disabled/foo.js | 3 + .../cli-colors-disabled/webpack.config.js | 13 +++ test/fixtures/cli-colors-enabled/foo.js | 3 + .../cli-colors-enabled/webpack.config.js | 13 +++ test/server/utils/createCertificate.test.js | 16 --- test/server/utils/getColorsOption.test.js | 96 ---------------- 15 files changed, 292 insertions(+), 239 deletions(-) delete mode 100644 lib/utils/createCertificate.js delete mode 100644 lib/utils/getCertificate.js create mode 100644 test/cli/__snapshots__/colors.test.js.snap.webpack4 create mode 100644 test/cli/__snapshots__/colors.test.js.snap.webpack5 create mode 100644 test/cli/colors.test.js create mode 100644 test/fixtures/cli-colors-default-stats/foo.js create mode 100644 test/fixtures/cli-colors-default-stats/webpack.config.js create mode 100644 test/fixtures/cli-colors-disabled/foo.js create mode 100644 test/fixtures/cli-colors-disabled/webpack.config.js create mode 100644 test/fixtures/cli-colors-enabled/foo.js create mode 100644 test/fixtures/cli-colors-enabled/webpack.config.js delete mode 100644 test/server/utils/createCertificate.test.js delete mode 100644 test/server/utils/getColorsOption.test.js diff --git a/lib/Server.js b/lib/Server.js index 7081926f0f..770a6283d1 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -39,7 +39,12 @@ class Server { // this value of web socket can be overwritten for tests this.webSocketHeartbeatInterval = 30000; - normalizeOptions(this.compiler, this.options, this.logger); + normalizeOptions( + this.compiler, + this.options, + this.logger, + Server.findCacheDir() + ); this.applyDevServerPlugin(); diff --git a/lib/utils/createCertificate.js b/lib/utils/createCertificate.js deleted file mode 100644 index e701f8d559..0000000000 --- a/lib/utils/createCertificate.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -const selfsigned = require('selfsigned'); - -function createCertificate(attributes) { - return selfsigned.generate(attributes, { - algorithm: 'sha256', - days: 30, - keySize: 2048, - extensions: [ - // { - // name: 'basicConstraints', - // cA: true, - // }, - { - name: 'keyUsage', - keyCertSign: true, - digitalSignature: true, - nonRepudiation: true, - keyEncipherment: true, - dataEncipherment: true, - }, - { - name: 'extKeyUsage', - serverAuth: true, - clientAuth: true, - codeSigning: true, - timeStamping: true, - }, - { - name: 'subjectAltName', - altNames: [ - { - // type 2 is DNS - type: 2, - value: 'localhost', - }, - { - type: 2, - value: 'localhost.localdomain', - }, - { - type: 2, - value: 'lvh.me', - }, - { - type: 2, - value: '*.lvh.me', - }, - { - type: 2, - value: '[::1]', - }, - { - // type 7 is IP - type: 7, - ip: '127.0.0.1', - }, - { - type: 7, - ip: 'fe80::1', - }, - ], - }, - ], - }); -} - -module.exports = createCertificate; diff --git a/lib/utils/getCertificate.js b/lib/utils/getCertificate.js deleted file mode 100644 index 7179979c19..0000000000 --- a/lib/utils/getCertificate.js +++ /dev/null @@ -1,50 +0,0 @@ -'use strict'; - -const path = require('path'); -const os = require('os'); -const fs = require('graceful-fs'); -const del = require('del'); -const Server = require('../Server'); -const createCertificate = require('./createCertificate'); - -function getCertificate(logger) { - // Use a self-signed certificate if no certificate was configured. - // Cycle certs every 24 hours - const certificateDir = - Server.findCacheDir({ name: 'webpack-dev-server' }) || os.tmpdir(); - const certificatePath = path.join(certificateDir, 'server.pem'); - - let certificateExists = fs.existsSync(certificatePath); - - if (certificateExists) { - const certificateTtl = 1000 * 60 * 60 * 24; - const certificateStat = fs.statSync(certificatePath); - - const now = new Date(); - - // cert is more than 30 days old, kill it with fire - if ((now - certificateStat.ctime) / certificateTtl > 30) { - logger.info('SSL Certificate is more than 30 days old. Removing.'); - - del.sync([certificatePath], { force: true }); - - certificateExists = false; - } - } - - if (!certificateExists) { - logger.info('Generating SSL Certificate'); - - const attributes = [{ name: 'commonName', value: 'localhost' }]; - const pems = createCertificate(attributes); - - fs.mkdirSync(certificateDir, { recursive: true }); - fs.writeFileSync(certificatePath, pems.private + pems.cert, { - encoding: 'utf8', - }); - } - - return fs.readFileSync(certificatePath); -} - -module.exports = getCertificate; diff --git a/lib/utils/normalizeOptions.js b/lib/utils/normalizeOptions.js index 0c6d0965ba..c6807308cb 100644 --- a/lib/utils/normalizeOptions.js +++ b/lib/utils/normalizeOptions.js @@ -1,14 +1,15 @@ 'use strict'; +const os = require('os'); const path = require('path'); +const del = require('del'); const fs = require('graceful-fs'); -const isAbsoluteUrl = require('is-absolute-url'); const getCompilerConfigArray = require('./getCompilerConfigArray'); -function normalizeOptions(compiler, options, logger) { +function normalizeOptions(compiler, options, logger, cacheDir) { // TODO: improve this to not use .find for compiler watchOptions - const configArr = getCompilerConfigArray(compiler); - const watchOptionsConfig = configArr.find( + const configArray = getCompilerConfigArray(compiler); + const watchOptionsConfig = configArray.find( (config) => config.watch !== false && config.watchOptions ); const watchOptions = watchOptionsConfig @@ -45,6 +46,8 @@ function normalizeOptions(compiler, options, logger) { } if (options.static) { + const isAbsoluteUrl = require('is-absolute-url'); + options.static.forEach((staticOption) => { if (isAbsoluteUrl(staticOption.directory)) { throw new Error('Using a URL as static.directory is not supported'); @@ -180,8 +183,6 @@ function normalizeOptions(compiler, options, logger) { // https option if (options.https) { - const getCertificate = require('./getCertificate'); - for (const property of ['cacert', 'pfx', 'key', 'cert']) { const value = options.https[property]; const isBuffer = value instanceof Buffer; @@ -205,7 +206,100 @@ function normalizeOptions(compiler, options, logger) { let fakeCert; if (!options.https.key || !options.https.cert) { - fakeCert = getCertificate(logger); + const certificateDir = cacheDir || os.tmpdir(); + const certificatePath = path.join(certificateDir, 'server.pem'); + let certificateExists = fs.existsSync(certificatePath); + + if (certificateExists) { + const certificateTtl = 1000 * 60 * 60 * 24; + const certificateStat = fs.statSync(certificatePath); + + const now = new Date(); + + // cert is more than 30 days old, kill it with fire + if ((now - certificateStat.ctime) / certificateTtl > 30) { + logger.info('SSL Certificate is more than 30 days old. Removing.'); + + del.sync([certificatePath], { force: true }); + + certificateExists = false; + } + } + + if (!certificateExists) { + logger.info('Generating SSL Certificate'); + + const selfsigned = require('selfsigned'); + const attributes = [{ name: 'commonName', value: 'localhost' }]; + const pems = selfsigned.generate(attributes, { + algorithm: 'sha256', + days: 30, + keySize: 2048, + extensions: [ + // { + // name: 'basicConstraints', + // cA: true, + // }, + { + name: 'keyUsage', + keyCertSign: true, + digitalSignature: true, + nonRepudiation: true, + keyEncipherment: true, + dataEncipherment: true, + }, + { + name: 'extKeyUsage', + serverAuth: true, + clientAuth: true, + codeSigning: true, + timeStamping: true, + }, + { + name: 'subjectAltName', + altNames: [ + { + // type 2 is DNS + type: 2, + value: 'localhost', + }, + { + type: 2, + value: 'localhost.localdomain', + }, + { + type: 2, + value: 'lvh.me', + }, + { + type: 2, + value: '*.lvh.me', + }, + { + type: 2, + value: '[::1]', + }, + { + // type 7 is IP + type: 7, + ip: '127.0.0.1', + }, + { + type: 7, + ip: 'fe80::1', + }, + ], + }, + ], + }); + + fs.mkdirSync(certificateDir, { recursive: true }); + fs.writeFileSync(certificatePath, pems.private + pems.cert, { + encoding: 'utf8', + }); + } + + fakeCert = fs.readFileSync(certificatePath); } options.https.key = options.https.key || fakeCert; diff --git a/test/cli/__snapshots__/colors.test.js.snap.webpack4 b/test/cli/__snapshots__/colors.test.js.snap.webpack4 new file mode 100644 index 0000000000..e785d87391 --- /dev/null +++ b/test/cli/__snapshots__/colors.test.js.snap.webpack4 @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`colors should work and do not use colors using configuration with disabled colors: stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + +exports[`colors should work do not use colors using "--no-color": stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + +exports[`colors should work use colors by default: stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + +exports[`colors should work use colors using "--color": stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + +exports[`colors should work use colors using configuration with enabled colors: stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; diff --git a/test/cli/__snapshots__/colors.test.js.snap.webpack5 b/test/cli/__snapshots__/colors.test.js.snap.webpack5 new file mode 100644 index 0000000000..e785d87391 --- /dev/null +++ b/test/cli/__snapshots__/colors.test.js.snap.webpack5 @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`colors should work and do not use colors using configuration with disabled colors: stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + +exports[`colors should work do not use colors using "--no-color": stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + +exports[`colors should work use colors by default: stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + +exports[`colors should work use colors using "--color": stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; + +exports[`colors should work use colors using configuration with enabled colors: stderr 1`] = ` +" [webpack-dev-server] Project is running at: + [webpack-dev-server] Loopback: http://localhost:/ + [webpack-dev-server] On Your Network (IPv4): http://:/ + [webpack-dev-server] On Your Network (IPv6): http://[]:/ + [webpack-dev-server] Content not from webpack is served from '/public' directory" +`; diff --git a/test/cli/colors.test.js b/test/cli/colors.test.js new file mode 100644 index 0000000000..c9053c503d --- /dev/null +++ b/test/cli/colors.test.js @@ -0,0 +1,58 @@ +'use strict'; + +const { testBin, normalizeStderr } = require('../helpers/test-bin'); + +const colorsDefaultStats = require.resolve( + '../fixtures/cli-colors-default-stats/webpack.config' +); +const colorsDisabled = require.resolve( + '../fixtures/cli-colors-disabled/webpack.config' +); +const colorsEnabled = require.resolve( + '../fixtures/cli-colors-enabled/webpack.config' +); + +describe('colors', () => { + it('should work use colors by default', async () => { + const { exitCode, stderr, stdout } = await testBin( + '--color', + colorsDefaultStats + ); + + expect(exitCode).toEqual(0); + expect(normalizeStderr(stderr, { ipv6: true })).toMatchSnapshot('stderr'); + expect(stdout).toContain('\x1b[1m'); + }); + + it('should work use colors using "--color"', async () => { + const { exitCode, stderr, stdout } = await testBin('--color'); + + expect(exitCode).toEqual(0); + expect(normalizeStderr(stderr, { ipv6: true })).toMatchSnapshot('stderr'); + expect(stdout).toContain('\x1b[1m'); + }); + + it('should work do not use colors using "--no-color"', async () => { + const { exitCode, stderr, stdout } = await testBin('--no-color'); + + expect(exitCode).toEqual(0); + expect(normalizeStderr(stderr, { ipv6: true })).toMatchSnapshot('stderr'); + expect(stdout).not.toContain('\x1b[1m'); + }); + + it('should work use colors using configuration with enabled colors', async () => { + const { exitCode, stderr, stdout } = await testBin('', colorsEnabled); + + expect(exitCode).toEqual(0); + expect(normalizeStderr(stderr, { ipv6: true })).toMatchSnapshot('stderr'); + expect(stdout).toContain('\x1b[1m'); + }); + + it('should work and do not use colors using configuration with disabled colors', async () => { + const { exitCode, stderr, stdout } = await testBin('', colorsDisabled); + + expect(exitCode).toEqual(0); + expect(normalizeStderr(stderr, { ipv6: true })).toMatchSnapshot('stderr'); + expect(stdout).not.toContain('\x1b[1m'); + }); +}); diff --git a/test/fixtures/cli-colors-default-stats/foo.js b/test/fixtures/cli-colors-default-stats/foo.js new file mode 100644 index 0000000000..f88d8b5040 --- /dev/null +++ b/test/fixtures/cli-colors-default-stats/foo.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('i am foo!'); diff --git a/test/fixtures/cli-colors-default-stats/webpack.config.js b/test/fixtures/cli-colors-default-stats/webpack.config.js new file mode 100644 index 0000000000..4e4bf0d660 --- /dev/null +++ b/test/fixtures/cli-colors-default-stats/webpack.config.js @@ -0,0 +1,10 @@ +'use strict'; + +const ExitOnDonePlugin = require('../../helpers/ExitOnDonePlugin'); + +module.exports = { + mode: 'development', + context: __dirname, + entry: './foo.js', + plugins: [ExitOnDonePlugin], +}; diff --git a/test/fixtures/cli-colors-disabled/foo.js b/test/fixtures/cli-colors-disabled/foo.js new file mode 100644 index 0000000000..f88d8b5040 --- /dev/null +++ b/test/fixtures/cli-colors-disabled/foo.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('i am foo!'); diff --git a/test/fixtures/cli-colors-disabled/webpack.config.js b/test/fixtures/cli-colors-disabled/webpack.config.js new file mode 100644 index 0000000000..8edb25ec41 --- /dev/null +++ b/test/fixtures/cli-colors-disabled/webpack.config.js @@ -0,0 +1,13 @@ +'use strict'; + +const ExitOnDonePlugin = require('../../helpers/ExitOnDonePlugin'); + +module.exports = { + mode: 'development', + stats: { + colors: false, + }, + context: __dirname, + entry: './foo.js', + plugins: [ExitOnDonePlugin], +}; diff --git a/test/fixtures/cli-colors-enabled/foo.js b/test/fixtures/cli-colors-enabled/foo.js new file mode 100644 index 0000000000..f88d8b5040 --- /dev/null +++ b/test/fixtures/cli-colors-enabled/foo.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('i am foo!'); diff --git a/test/fixtures/cli-colors-enabled/webpack.config.js b/test/fixtures/cli-colors-enabled/webpack.config.js new file mode 100644 index 0000000000..e4dc935a8d --- /dev/null +++ b/test/fixtures/cli-colors-enabled/webpack.config.js @@ -0,0 +1,13 @@ +'use strict'; + +const ExitOnDonePlugin = require('../../helpers/ExitOnDonePlugin'); + +module.exports = { + mode: 'development', + stats: { + colors: true, + }, + context: __dirname, + entry: './foo.js', + plugins: [ExitOnDonePlugin], +}; diff --git a/test/server/utils/createCertificate.test.js b/test/server/utils/createCertificate.test.js deleted file mode 100644 index 3a23e99efb..0000000000 --- a/test/server/utils/createCertificate.test.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -const createCertificate = require('../../../lib/utils/createCertificate'); - -describe('createCertificate', () => { - it('should have keys', () => { - expect(createCertificate([{ name: 'commonName', value: 'wds' }])).toEqual( - expect.objectContaining({ - private: expect.any(String), - public: expect.any(String), - cert: expect.any(String), - fingerprint: expect.any(String), - }) - ); - }); -}); diff --git a/test/server/utils/getColorsOption.test.js b/test/server/utils/getColorsOption.test.js deleted file mode 100644 index 87e7a36913..0000000000 --- a/test/server/utils/getColorsOption.test.js +++ /dev/null @@ -1,96 +0,0 @@ -'use strict'; - -const getColorsOption = require('../../../lib/utils/getColorsOption'); - -describe('getColorsOption', () => { - it('should return false for empty config array', () => { - expect(getColorsOption([])).toEqual(false); - }); - - it('should return false for config array with no colors option', () => { - expect( - getColorsOption([ - { - entry: './index.js', - }, - ]) - ).toEqual(false); - }); - - it('should return false for config array with stats string but no colors option', () => { - expect( - getColorsOption([ - { - stats: 'verbose', - }, - ]) - ).toEqual(false); - }); - - it('should return false for config array with stats object but no colors option', () => { - expect( - getColorsOption([ - { - stats: { - cached: false, - }, - }, - ]) - ).toEqual(false); - }); - - it('should return false for first stats option with no colors option', () => { - expect( - getColorsOption([ - { - stats: { - cached: false, - }, - }, - { - stats: { - colors: true, - }, - }, - ]) - ).toEqual(false); - }); - - it('should return true for first stats option that has true colors option', () => { - expect( - getColorsOption([ - { - stats: { - colors: true, - }, - }, - { - stats: { - cached: false, - }, - }, - ]) - ).toEqual(true); - }); - - it('should return object for first stats option that has object colors option', () => { - expect( - getColorsOption([ - { - stats: { - colors: { - green: '\u001b[32m', - }, - }, - }, - { - stats: { - cached: false, - }, - }, - ]) - ).toEqual({ - green: '\u001b[32m', - }); - }); -}); From 73679e13d33c92027cbed0fdf3b28ac5212854f2 Mon Sep 17 00:00:00 2001 From: evilebottnawi Date: Mon, 21 Jun 2021 17:33:44 +0300 Subject: [PATCH 12/12] refactor: fix merge --- lib/Server.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Server.js b/lib/Server.js index 770a6283d1..babaf9d40c 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -124,8 +124,8 @@ class Server { function runPortFinder() { return new Promise((resolve, reject) => { - // default port - portfinder.basePort = 8080; + // Default port + portfinder.basePort = process.env.WEBPACK_DEV_SERVER_BASE_PORT || 8080; portfinder.getPort((error, foundPort) => { if (error) { return reject(error); @@ -138,7 +138,8 @@ class Server { // Try to find unused port and listen on it for 3 times, // if port is not specified in options. - const defaultPortRetry = parseInt(process.env.DEFAULT_PORT_RETRY, 10) || 3; + const defaultPortRetry = + parseInt(process.env.WEBPACK_DEV_SERVER_PORT_RETRY, 10) || 3; return pRetry(runPortFinder, { retries: defaultPortRetry }); }