webpack-dev-server
Advanced tools
Comparing version 3.11.0 to 4.0.0-beta.0
@@ -18,35 +18,17 @@ 'use strict'; | ||
{ | ||
name: 'lazy', | ||
name: 'live-reload', | ||
type: Boolean, | ||
describe: 'Lazy', | ||
}, | ||
{ | ||
name: 'liveReload', | ||
type: Boolean, | ||
defaultValue: true, | ||
describe: 'Enables/Disables live reloading on changing files', | ||
negative: true, | ||
}, | ||
{ | ||
name: 'serveIndex', | ||
name: 'client-progress', | ||
type: Boolean, | ||
describe: 'Enables/Disables serveIndex middleware', | ||
defaultValue: true, | ||
}, | ||
{ | ||
name: 'inline', | ||
type: Boolean, | ||
defaultValue: true, | ||
describe: | ||
'Inline mode (set to false to disable including client scripts like livereload)', | ||
}, | ||
{ | ||
name: 'profile', | ||
type: Boolean, | ||
describe: 'Print compilation profile data for progress steps', | ||
}, | ||
{ | ||
name: 'progress', | ||
type: Boolean, | ||
describe: 'Print compilation progress in percentage', | ||
describe: 'Print compilation progress in percentage in the browser', | ||
group: BASIC_GROUP, | ||
processor(opts) { | ||
opts.client = opts.client || {}; | ||
opts.client.progress = opts.clientProgress; | ||
delete opts.clientProgress; | ||
}, | ||
}, | ||
@@ -58,4 +40,16 @@ { | ||
group: ADVANCED_GROUP, | ||
processor(opts) { | ||
opts.hot = 'only'; | ||
delete opts.hotOnly; | ||
}, | ||
}, | ||
{ | ||
name: 'setup-exit-signals', | ||
type: Boolean, | ||
describe: 'Close and exit the process on SIGINT and SIGTERM', | ||
group: ADVANCED_GROUP, | ||
defaultValue: true, | ||
negative: true, | ||
}, | ||
{ | ||
name: 'stdin', | ||
@@ -67,3 +61,3 @@ type: Boolean, | ||
name: 'open', | ||
type: String, | ||
type: [String, Boolean], | ||
describe: | ||
@@ -73,3 +67,3 @@ 'Open the default browser, or optionally specify a browser name', | ||
{ | ||
name: 'useLocalIp', | ||
name: 'use-local-ip', | ||
type: Boolean, | ||
@@ -82,10 +76,15 @@ describe: 'Open default browser with local IP', | ||
describe: 'Open default browser with the specified page', | ||
multiple: true, | ||
}, | ||
{ | ||
name: 'client-log-level', | ||
name: 'client-logging', | ||
type: String, | ||
group: DISPLAY_GROUP, | ||
defaultValue: 'info', | ||
describe: | ||
'Log level in the browser (trace, debug, info, warn, error or silent)', | ||
'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; | ||
}, | ||
}, | ||
@@ -105,44 +104,10 @@ { | ||
{ | ||
name: 'key', | ||
type: String, | ||
describe: 'Path to a SSL key.', | ||
group: SSL_GROUP, | ||
}, | ||
{ | ||
name: 'cert', | ||
type: String, | ||
describe: 'Path to a SSL certificate.', | ||
group: SSL_GROUP, | ||
}, | ||
{ | ||
name: 'cacert', | ||
type: String, | ||
describe: 'Path to a SSL CA certificate.', | ||
group: SSL_GROUP, | ||
}, | ||
{ | ||
name: 'pfx', | ||
type: String, | ||
describe: 'Path to a SSL pfx file.', | ||
group: SSL_GROUP, | ||
}, | ||
{ | ||
name: 'pfx-passphrase', | ||
type: String, | ||
describe: 'Passphrase for pfx file.', | ||
group: SSL_GROUP, | ||
}, | ||
{ | ||
name: 'content-base', | ||
type: String, | ||
describe: 'A directory or URL to serve HTML content from.', | ||
name: 'static', | ||
type: [String, Boolean], | ||
describe: 'A directory to serve static content from.', | ||
group: RESPONSE_GROUP, | ||
multiple: true, | ||
negative: true, | ||
}, | ||
{ | ||
name: 'watch-content-base', | ||
type: Boolean, | ||
describe: 'Enable live-reloading of the content-base.', | ||
group: RESPONSE_GROUP, | ||
}, | ||
{ | ||
name: 'history-api-fallback', | ||
@@ -159,3 +124,2 @@ type: Boolean, | ||
}, | ||
// findPort is currently not set up | ||
{ | ||
@@ -168,14 +132,2 @@ name: 'port', | ||
{ | ||
name: 'disable-host-check', | ||
type: Boolean, | ||
describe: 'Will not check the host', | ||
group: CONNECTION_GROUP, | ||
}, | ||
{ | ||
name: 'socket', | ||
type: String, | ||
describe: 'Socket to listen', | ||
group: CONNECTION_GROUP, | ||
}, | ||
{ | ||
name: 'public', | ||
@@ -192,9 +144,7 @@ type: String, | ||
}, | ||
// use command-line-args "multiple" option, allowing the usage: --allowed-hosts host1 host2 host3 | ||
// instead of the old, comma-separated syntax: --allowed-hosts host1,host2,host3 | ||
{ | ||
name: 'allowed-hosts', | ||
name: 'firewall', | ||
type: String, | ||
describe: | ||
'A list of hosts that are allowed to access the dev server, separated by spaces', | ||
'Enable/disable firewall, or set hosts that are allowed to access the dev server', | ||
group: CONNECTION_GROUP, | ||
@@ -201,0 +151,0 @@ multiple: true, |
#!/usr/bin/env node | ||
/* Based on webpack/bin/webpack.js */ | ||
/* eslint-disable no-console */ | ||
'use strict'; | ||
/* eslint-disable no-shadow, no-console */ | ||
/** | ||
* @param {string} command process to run | ||
* @param {string[]} args command line arguments | ||
* @returns {Promise<void>} promise | ||
*/ | ||
const runCommand = (command, args) => { | ||
const cp = require('child_process'); | ||
return new Promise((resolve, reject) => { | ||
const executedCommand = cp.spawn(command, args, { | ||
stdio: 'inherit', | ||
shell: true, | ||
}); | ||
const fs = require('fs'); | ||
const net = require('net'); | ||
const debug = require('debug')('webpack-dev-server'); | ||
const importLocal = require('import-local'); | ||
const yargs = require('yargs'); | ||
const webpack = require('webpack'); | ||
const Server = require('../lib/Server'); | ||
const setupExitSignals = require('../lib/utils/setupExitSignals'); | ||
const colors = require('../lib/utils/colors'); | ||
const processOptions = require('../lib/utils/processOptions'); | ||
const createLogger = require('../lib/utils/createLogger'); | ||
const getVersions = require('../lib/utils/getVersions'); | ||
const options = require('./options'); | ||
executedCommand.on('error', (error) => { | ||
reject(error); | ||
}); | ||
let server; | ||
const serverData = { | ||
server: null, | ||
executedCommand.on('exit', (code) => { | ||
if (code === 0) { | ||
resolve(); | ||
} else { | ||
reject(); | ||
} | ||
}); | ||
}); | ||
}; | ||
// we must pass an object that contains the server object as a property so that | ||
// we can update this server property later, and setupExitSignals will be able to | ||
// recognize that the server has been instantiated, because we will set | ||
// serverData.server to the new server object. | ||
setupExitSignals(serverData); | ||
// Prefer the local installation of webpack-dev-server | ||
if (importLocal(__filename)) { | ||
debug('Using local install of webpack-dev-server'); | ||
/** | ||
* @param {string} packageName name of the package | ||
* @returns {boolean} is the package installed? | ||
*/ | ||
const isInstalled = (packageName) => { | ||
try { | ||
require.resolve(packageName); | ||
return; | ||
} | ||
return true; | ||
} catch (err) { | ||
return false; | ||
} | ||
}; | ||
try { | ||
require.resolve('webpack-cli'); | ||
} catch (err) { | ||
console.error('The CLI moved into a separate package: webpack-cli'); | ||
console.error( | ||
"Please install 'webpack-cli' in addition to webpack itself to use the CLI" | ||
); | ||
console.error('-> When using npm: npm i -D webpack-cli'); | ||
console.error('-> When using yarn: yarn add -D webpack-cli'); | ||
/** | ||
* @param {CliOption} cli options | ||
* @returns {void} | ||
*/ | ||
const runCli = (cli) => { | ||
if (cli.preprocess) { | ||
cli.preprocess(); | ||
} | ||
const path = require('path'); | ||
const pkgPath = require.resolve(`${cli.package}/package.json`); | ||
// eslint-disable-next-line import/no-dynamic-require | ||
const pkg = require(pkgPath); | ||
// eslint-disable-next-line import/no-dynamic-require | ||
require(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName])); | ||
}; | ||
process.exitCode = 1; | ||
} | ||
/** | ||
* @typedef {Object} CliOption | ||
* @property {string} name display name | ||
* @property {string} package npm package name | ||
* @property {string} binName name of the executable file | ||
* @property {boolean} installed currently installed? | ||
* @property {string} url homepage | ||
* @property {function} preprocess preprocessor | ||
*/ | ||
yargs.usage( | ||
`${getVersions()}\nUsage: https://webpack.js.org/configuration/dev-server/` | ||
); | ||
/** @type {CliOption} */ | ||
const cli = { | ||
name: 'webpack-cli', | ||
package: 'webpack-cli', | ||
binName: 'webpack-cli', | ||
installed: isInstalled('webpack-cli'), | ||
url: 'https://github.com/webpack/webpack-cli', | ||
preprocess() { | ||
process.argv.splice(2, 0, 'serve'); | ||
}, | ||
}; | ||
// webpack-cli@3.3 path : 'webpack-cli/bin/config/config-yargs' | ||
let configYargsPath; | ||
try { | ||
require.resolve('webpack-cli/bin/config/config-yargs'); | ||
configYargsPath = 'webpack-cli/bin/config/config-yargs'; | ||
} catch (e) { | ||
configYargsPath = 'webpack-cli/bin/config-yargs'; | ||
} | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
// eslint-disable-next-line import/no-dynamic-require | ||
require(configYargsPath)(yargs); | ||
if (!cli.installed) { | ||
const path = require('path'); | ||
const fs = require('graceful-fs'); | ||
const readLine = require('readline'); | ||
// It is important that this is done after the webpack yargs config, | ||
// so it overrides webpack's version info. | ||
yargs.version(getVersions()); | ||
yargs.options(options); | ||
const notify = `CLI for webpack must be installed.\n ${cli.name} (${cli.url})\n`; | ||
const argv = yargs.argv; | ||
console.error(notify); | ||
// webpack-cli@3.3 path : 'webpack-cli/bin/utils/convert-argv' | ||
let convertArgvPath; | ||
try { | ||
require.resolve('webpack-cli/bin/utils/convert-argv'); | ||
convertArgvPath = 'webpack-cli/bin/utils/convert-argv'; | ||
} catch (e) { | ||
convertArgvPath = 'webpack-cli/bin/convert-argv'; | ||
} | ||
// eslint-disable-next-line import/no-extraneous-dependencies | ||
// eslint-disable-next-line import/no-dynamic-require | ||
const config = require(convertArgvPath)(yargs, argv, { | ||
outputFilename: '/bundle.js', | ||
}); | ||
let packageManager; | ||
function startDevServer(config, options) { | ||
const log = createLogger(options); | ||
if (fs.existsSync(path.resolve(process.cwd(), 'yarn.lock'))) { | ||
packageManager = 'yarn'; | ||
} else if (fs.existsSync(path.resolve(process.cwd(), 'pnpm-lock.yaml'))) { | ||
packageManager = 'pnpm'; | ||
} else { | ||
packageManager = 'npm'; | ||
} | ||
let compiler; | ||
const installOptions = [packageManager === 'yarn' ? 'add' : 'install', '-D']; | ||
try { | ||
compiler = webpack(config); | ||
} catch (err) { | ||
if (err instanceof webpack.WebpackOptionsValidationError) { | ||
log.error(colors.error(options.stats.colors, err.message)); | ||
// eslint-disable-next-line no-process-exit | ||
process.exit(1); | ||
} | ||
console.error( | ||
`We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join( | ||
' ' | ||
)}".` | ||
); | ||
throw err; | ||
} | ||
const question = `Do you want to install 'webpack-cli' (yes/no): `; | ||
try { | ||
server = new Server(compiler, options, log); | ||
serverData.server = server; | ||
} catch (err) { | ||
if (err.name === 'ValidationError') { | ||
log.error(colors.error(options.stats.colors, err.message)); | ||
// eslint-disable-next-line no-process-exit | ||
process.exit(1); | ||
} | ||
const questionInterface = readLine.createInterface({ | ||
input: process.stdin, | ||
output: process.stderr, | ||
}); | ||
throw err; | ||
} | ||
// In certain scenarios (e.g. when STDIN is not in terminal mode), the callback function will not be | ||
// executed. Setting the exit code here to ensure the script exits correctly in those cases. The callback | ||
// function is responsible for clearing the exit code if the user wishes to install webpack-cli. | ||
process.exitCode = 1; | ||
questionInterface.question(question, (answer) => { | ||
questionInterface.close(); | ||
if (options.socket) { | ||
server.listeningApp.on('error', (e) => { | ||
if (e.code === 'EADDRINUSE') { | ||
const clientSocket = new net.Socket(); | ||
const normalizedAnswer = answer.toLowerCase().startsWith('y'); | ||
clientSocket.on('error', (err) => { | ||
if (err.code === 'ECONNREFUSED') { | ||
// No other server listening on this socket so it can be safely removed | ||
fs.unlinkSync(options.socket); | ||
if (!normalizedAnswer) { | ||
console.error( | ||
"You need to install 'webpack-cli' to use webpack via CLI.\n" + | ||
'You can also install the CLI manually.' | ||
); | ||
server.listen(options.socket, options.host, (error) => { | ||
if (error) { | ||
throw error; | ||
} | ||
}); | ||
} | ||
}); | ||
return; | ||
} | ||
process.exitCode = 0; | ||
clientSocket.connect({ path: options.socket }, () => { | ||
throw new Error('This socket is already used'); | ||
}); | ||
} | ||
}); | ||
console.log( | ||
`Installing '${ | ||
cli.package | ||
}' (running '${packageManager} ${installOptions.join(' ')} ${ | ||
cli.package | ||
}')...` | ||
); | ||
server.listen(options.socket, options.host, (err) => { | ||
if (err) { | ||
throw err; | ||
} | ||
// chmod 666 (rw rw rw) | ||
const READ_WRITE = 438; | ||
fs.chmod(options.socket, READ_WRITE, (err) => { | ||
if (err) { | ||
throw err; | ||
} | ||
runCommand(packageManager, installOptions.concat(cli.package)) | ||
.then(() => { | ||
runCli(cli); | ||
}) | ||
.catch((error) => { | ||
console.error(error); | ||
process.exitCode = 1; | ||
}); | ||
}); | ||
} else { | ||
server.listen(options.port, options.host, (err) => { | ||
if (err) { | ||
throw err; | ||
} | ||
}); | ||
} | ||
}); | ||
} else { | ||
runCli(cli); | ||
} | ||
processOptions(config, argv, (config, options) => { | ||
startDevServer(config, options); | ||
}); |
117
CHANGELOG.md
@@ -5,2 +5,119 @@ # Changelog | ||
## [4.0.0-beta.0](https://github.com/webpack/webpack-dev-server/compare/v3.11.0...v4.0.0-beta.0) (2020-11-27) | ||
### ⚠ BREAKING CHANGES | ||
* drop support `Node.js@6` and `Node.js@8`, minimum supported `Node.js` version is `Node@10` | ||
* the `hot` option is `true` by default | ||
* the `hotOnly` option was removed, if you need hot only mode, use `hot: 'only'` value | ||
* the default `transportMode` is switched from `sockjs` to `ws` (IE 11 and other old browsers doesn't support WebSocket, set `sockjs` value for `transportMode` if you need supports IE 11) | ||
* `before`, `after` and `setup` were removed in favor `onBeforeSetupMiddleware` (previously `before`) and `onAfterSetupMiddleware` options (previously `after`) | ||
* the `clientOptions` was renamed to the `client` option | ||
* the `key`, `cert`, `pfx`, `pfx-passphrase`, `cacert`, `ca` and `requestCert` options were moved to `https` options, please use `https.{key|cert|pfx|passphrase|requestCert|cacert|ca|requestCert}` | ||
* the `sockHost`, `sockPath` and `sockPort` options were removed in `client` option | ||
* the `inline` option (`iframe` live mode) was removed | ||
* the `lazy` and `filename` options were removed | ||
* the `features` option was removed | ||
* the `log`, `logLevel`, `logTime`, `noInfo`, `quiet`, `reporter` and `warn` options were removed in favor of built-in webpack logger, please read [this](https://webpack.js.org/configuration/other-options/#infrastructurelogginglevel) to enable and setup logging output | ||
* the `fs`, `index`, `mimeTypes`, `publicPath`, `serverSideRender`, and `writeToDisk` options were moved in the `dev` option (`webpack-dev-middleware` options) | ||
* updating `webpack-dev-middleware` to v4, which includes many breaking options changes, please [read](https://github.com/webpack/webpack-dev-middleware/releases) | ||
* the `stats` option was removed, please use the [`stats`](https://webpack.js.org/configuration/stats/) option from `webpack.config.js` | ||
* the `socket` option was removed | ||
* the `contentBase`, `contentBasePublicPath`, `serveIndex`, `staticOptions`, `watchContentBase`, `watchOptions` were removed in favor of the `static` option | ||
* the `disableHostCheck` and `allowedHosts` options were removed in favor of the `firewall` option | ||
* `server.listen()` will find free port if the `port` is not set and the `port` argument is not passed, also print a warning if the `port` option and the `port` argument passed to `server.listen()` are different | ||
* the `progress` option is moved to the `client` option, set `client: {progress: true}` | ||
* the `profile` option was removed, to print profile data, set `client: { progress: 'profile' }` | ||
* client uses the port of the current location (`location.port`, equivalent to `sockPort: 'location'`), by default. To get previously behavior, set the `client.port` with the port you'd like to set | ||
* client uses the hostname of the current location (`location.hostname`), by default. To get previously behavior, set the `client.host` with the hostname you'd like to set | ||
### Features | ||
* compatibility with `webpack@5` | ||
* compatibility with `webpack-cli@4` | ||
* added the `setupExitSignals` option, it takes a boolean and if true (default on CLI), the server will close and exit the process on SIGINT and SIGTERM | ||
* update `chokidar` to v3 | ||
### Notes | ||
Unfortunately, due to the huge amount of changes it is very difficult to display all changes in a convenient form. Therefore, we offer you a couple of popular examples (feel free to send a PR with more examples). | ||
#### `static` | ||
Previously `contentBase`, `contentBasePublicPath`, `serveIndex`, `staticOptions`, `watchContentBase` and `watchOptions` | ||
```js | ||
module.exports = { | ||
// ... | ||
devServer: { | ||
// Can be: | ||
// static: path.resolve(__dirname, 'static') | ||
// static: false | ||
static: [ | ||
// Simple example | ||
path.resolve(__dirname, 'static'), | ||
// Complex example | ||
{ | ||
directory: path.resolve(__dirname, 'static'), | ||
staticOptions: {}, | ||
// Don't be confused with `dev.publicPath`, it is `publicPath` for static directory | ||
// Can be: | ||
// publicPath: ['/static-public-path-one/', '/static-public-path-two/'], | ||
publicPath: '/static-public-path/', | ||
// Can be: | ||
// serveIndex: {} (options for the `serveIndex` option you can find https://github.com/expressjs/serve-index) | ||
serveIndex: true, | ||
// Can be: | ||
// watch: {} (options for the `watch` option you can find https://github.com/paulmillr/chokidar) | ||
watch: true, | ||
}, | ||
], | ||
}, | ||
}; | ||
``` | ||
#### `publicPath` | ||
```js | ||
module.exports = { | ||
// ... | ||
devServer: { | ||
dev: { | ||
publicPath: '/publicPathForDevServe', | ||
}, | ||
}, | ||
}; | ||
``` | ||
#### `firewall` | ||
Previously `disableHostCheck` and `allowedHosts` | ||
```js | ||
module.exports = { | ||
// ... | ||
devServer: { | ||
dev: { | ||
// Can be | ||
// firewall: ['192.168.0.1', 'domain.com'] | ||
firewall: false, | ||
}, | ||
}, | ||
}; | ||
``` | ||
#### logging | ||
```js | ||
module.exports = { | ||
// ... | ||
infrastructureLogging: { | ||
// Only warnings and errors | ||
// level: 'none' disable logging | ||
// Please read https://webpack.js.org/configuration/other-options/#infrastructurelogginglevel | ||
level: 'warn', | ||
}, | ||
}; | ||
``` | ||
## [3.11.0](https://github.com/webpack/webpack-dev-server/compare/v3.10.3...v3.11.0) (2020-05-08) | ||
@@ -7,0 +124,0 @@ |
'use strict'; | ||
/* eslint-disable | ||
no-unused-vars | ||
*/ | ||
@@ -19,2 +16,3 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
key: "getClientPath", | ||
// eslint-disable-next-line no-unused-vars | ||
value: function getClientPath(options) { | ||
@@ -21,0 +19,0 @@ throw new Error('Client needs implementation'); |
'use strict'; | ||
/* eslint-disable | ||
no-unused-vars | ||
*/ | ||
@@ -18,3 +15,3 @@ function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } | ||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } | ||
@@ -31,2 +28,5 @@ function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } | ||
var _require = require('../default/utils/log'), | ||
log = _require.log; | ||
var BaseClient = require('./BaseClient'); | ||
@@ -47,9 +47,10 @@ | ||
_this.sock.onerror = function (err) {// TODO: use logger to log the error event once client and client-src | ||
// are reorganized to have the same directory structure | ||
_this.sock.onerror = function (err) { | ||
log.error(err); | ||
}; | ||
return _this; | ||
} | ||
} // eslint-disable-next-line no-unused-vars | ||
_createClass(SockJSClient, [{ | ||
@@ -56,0 +57,0 @@ key: "onOpen", |
'use strict'; | ||
/* global WebSocket */ | ||
/* eslint-disable | ||
no-unused-vars | ||
*/ | ||
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
@@ -20,3 +16,3 @@ | ||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } | ||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } | ||
@@ -31,2 +27,5 @@ function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } | ||
var _require = require('../default/utils/log'), | ||
log = _require.log; | ||
var BaseClient = require('./BaseClient'); | ||
@@ -47,9 +46,10 @@ | ||
_this.client.onerror = function (err) {// TODO: use logger to log the error event once client and client-src | ||
// are reorganized to have the same directory structure | ||
_this.client.onerror = function (err) { | ||
log.error(err); | ||
}; | ||
return _this; | ||
} | ||
} // eslint-disable-next-line no-unused-vars | ||
_createClass(WebsocketClient, [{ | ||
@@ -56,0 +56,0 @@ key: "onOpen", |
{ | ||
"type": "object", | ||
"properties": { | ||
"after": { | ||
"instanceof": "Function" | ||
}, | ||
"allowedHosts": { | ||
"type": "array", | ||
"items": { | ||
"type": "string" | ||
"definitions": { | ||
"StaticObject": { | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"directory": { | ||
"type": "string", | ||
"minLength": 1 | ||
}, | ||
"staticOptions": { | ||
"type": "object" | ||
}, | ||
"publicPath": { | ||
"anyOf": [ | ||
{ | ||
"type": "string", | ||
"minLength": 1 | ||
}, | ||
{ | ||
"type": "array", | ||
"items": { | ||
"type": "string", | ||
"minLength": 1 | ||
}, | ||
"minItems": 1 | ||
} | ||
] | ||
}, | ||
"serveIndex": { | ||
"anyOf": [ | ||
{ | ||
"type": "boolean" | ||
}, | ||
{ | ||
"type": "object" | ||
} | ||
] | ||
}, | ||
"watch": { | ||
"anyOf": [ | ||
{ | ||
"type": "boolean" | ||
}, | ||
{ | ||
"type": "object" | ||
} | ||
] | ||
} | ||
} | ||
}, | ||
"before": { | ||
"instanceof": "Function" | ||
}, | ||
"StaticString": { | ||
"type": "string", | ||
"minLength": 1 | ||
} | ||
}, | ||
"properties": { | ||
"bonjour": { | ||
"type": "boolean" | ||
}, | ||
"ca": { | ||
"anyOf": [ | ||
{ | ||
"client": { | ||
"type": "object", | ||
"properties": { | ||
"host": { | ||
"type": "string" | ||
}, | ||
{ | ||
"instanceof": "Buffer" | ||
} | ||
] | ||
}, | ||
"cert": { | ||
"anyOf": [ | ||
{ | ||
"path": { | ||
"type": "string" | ||
}, | ||
{ | ||
"instanceof": "Buffer" | ||
"port": { | ||
"anyOf": [ | ||
{ | ||
"type": "number" | ||
}, | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"type": "null" | ||
} | ||
] | ||
}, | ||
"logging": { | ||
"enum": ["none", "error", "warn", "info", "log", "verbose"] | ||
}, | ||
"progress": { | ||
"type": "boolean" | ||
} | ||
] | ||
}, | ||
"additionalProperties": false | ||
}, | ||
"clientLogLevel": { | ||
"enum": [ | ||
"info", | ||
"warn", | ||
"error", | ||
"debug", | ||
"trace", | ||
"silent", | ||
"none", | ||
"warning" | ||
] | ||
}, | ||
"compress": { | ||
"type": "boolean" | ||
}, | ||
"contentBasePublicPath": { | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"type": "array", | ||
"items": { | ||
"type": "string" | ||
}, | ||
"minItems": 1 | ||
} | ||
] | ||
"dev": { | ||
"type": "object" | ||
}, | ||
"contentBase": { | ||
"firewall": { | ||
"anyOf": [ | ||
{ | ||
"enum": [false] | ||
"type": "boolean" | ||
}, | ||
{ | ||
"type": "number" | ||
}, | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"type": "array", | ||
@@ -88,27 +113,2 @@ "items": { | ||
}, | ||
"disableHostCheck": { | ||
"type": "boolean" | ||
}, | ||
"features": { | ||
"type": "array", | ||
"items": { | ||
"type": "string" | ||
} | ||
}, | ||
"filename": { | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"instanceof": "RegExp" | ||
}, | ||
{ | ||
"instanceof": "Function" | ||
} | ||
] | ||
}, | ||
"fs": { | ||
"type": "object" | ||
}, | ||
"headers": { | ||
@@ -138,7 +138,11 @@ "type": "object" | ||
"hot": { | ||
"type": "boolean" | ||
"anyOf": [ | ||
{ | ||
"type": "boolean" | ||
}, | ||
{ | ||
"enum": ["only"] | ||
} | ||
] | ||
}, | ||
"hotOnly": { | ||
"type": "boolean" | ||
}, | ||
"http2": { | ||
@@ -150,12 +154,58 @@ "type": "boolean" | ||
{ | ||
"type": "object" | ||
"type": "boolean" | ||
}, | ||
{ | ||
"type": "boolean" | ||
"type": "object", | ||
"additionalProperties": false, | ||
"properties": { | ||
"passphrase": { | ||
"type": "string" | ||
}, | ||
"requestCert": { | ||
"type": "boolean" | ||
}, | ||
"ca": { | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"instanceof": "Buffer" | ||
} | ||
] | ||
}, | ||
"key": { | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"instanceof": "Buffer" | ||
} | ||
] | ||
}, | ||
"pfx": { | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"instanceof": "Buffer" | ||
} | ||
] | ||
}, | ||
"cert": { | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"instanceof": "Buffer" | ||
} | ||
] | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
"index": { | ||
"type": "string" | ||
}, | ||
"injectClient": { | ||
@@ -181,36 +231,11 @@ "anyOf": [ | ||
}, | ||
"inline": { | ||
"type": "boolean" | ||
}, | ||
"key": { | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"instanceof": "Buffer" | ||
} | ||
] | ||
}, | ||
"lazy": { | ||
"type": "boolean" | ||
}, | ||
"liveReload": { | ||
"type": "boolean" | ||
}, | ||
"log": { | ||
"onAfterSetupMiddleware": { | ||
"instanceof": "Function" | ||
}, | ||
"logLevel": { | ||
"enum": ["info", "warn", "error", "debug", "trace", "silent"] | ||
"onBeforeSetupMiddleware": { | ||
"instanceof": "Function" | ||
}, | ||
"logTime": { | ||
"type": "boolean" | ||
}, | ||
"mimeTypes": { | ||
"type": "object" | ||
}, | ||
"noInfo": { | ||
"type": "boolean" | ||
}, | ||
"onListening": { | ||
@@ -264,15 +289,2 @@ "instanceof": "Function" | ||
}, | ||
"pfx": { | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ | ||
"instanceof": "Buffer" | ||
} | ||
] | ||
}, | ||
"pfxPassphrase": { | ||
"type": "string" | ||
}, | ||
"port": { | ||
@@ -291,8 +303,2 @@ "anyOf": [ | ||
}, | ||
"profile": { | ||
"type": "boolean" | ||
}, | ||
"progress": { | ||
"type": "boolean" | ||
}, | ||
"proxy": { | ||
@@ -322,68 +328,35 @@ "anyOf": [ | ||
}, | ||
"publicPath": { | ||
"type": "string" | ||
}, | ||
"quiet": { | ||
"setupExitSignals": { | ||
"type": "boolean" | ||
}, | ||
"reporter": { | ||
"instanceof": "Function" | ||
}, | ||
"requestCert": { | ||
"type": "boolean" | ||
}, | ||
"serveIndex": { | ||
"type": "boolean" | ||
}, | ||
"serverSideRender": { | ||
"type": "boolean" | ||
}, | ||
"setup": { | ||
"instanceof": "Function" | ||
}, | ||
"sockHost": { | ||
"type": "string" | ||
}, | ||
"sockPath": { | ||
"type": "string" | ||
}, | ||
"sockPort": { | ||
"static": { | ||
"anyOf": [ | ||
{ | ||
"type": "number" | ||
"type": "boolean" | ||
}, | ||
{ | ||
"type": "string" | ||
"$ref": "#/definitions/StaticString" | ||
}, | ||
{ | ||
"type": "null" | ||
} | ||
] | ||
}, | ||
"socket": { | ||
"type": "string" | ||
}, | ||
"staticOptions": { | ||
"type": "object" | ||
}, | ||
"stats": { | ||
"anyOf": [ | ||
{ | ||
"type": "object" | ||
"$ref": "#/definitions/StaticObject" | ||
}, | ||
{ | ||
"type": "boolean" | ||
}, | ||
{ | ||
"enum": [ | ||
"none", | ||
"errors-only", | ||
"errors-warnings", | ||
"minimal", | ||
"normal", | ||
"verbose" | ||
] | ||
"type": "array", | ||
"items": { | ||
"anyOf": [ | ||
{ | ||
"$ref": "#/definitions/StaticString" | ||
}, | ||
{ | ||
"$ref": "#/definitions/StaticObject" | ||
} | ||
] | ||
}, | ||
"minItems": 1 | ||
} | ||
] | ||
}, | ||
"stdin": { | ||
"type": "boolean" | ||
}, | ||
"transportMode": { | ||
@@ -417,21 +390,2 @@ "anyOf": [ | ||
"type": "boolean" | ||
}, | ||
"warn": { | ||
"instanceof": "Function" | ||
}, | ||
"watchContentBase": { | ||
"type": "boolean" | ||
}, | ||
"watchOptions": { | ||
"type": "object" | ||
}, | ||
"writeToDisk": { | ||
"anyOf": [ | ||
{ | ||
"type": "boolean" | ||
}, | ||
{ | ||
"instanceof": "Function" | ||
} | ||
] | ||
} | ||
@@ -441,34 +395,18 @@ }, | ||
"properties": { | ||
"after": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserverafter)", | ||
"allowedHosts": "should be {Array} (https://webpack.js.org/configuration/dev-server/#devserverallowedhosts)", | ||
"before": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserverbefore)", | ||
"bonjour": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverbonjour)", | ||
"ca": "should be {String|Buffer}", | ||
"cert": "should be {String|Buffer}", | ||
"clientLogLevel": "should be {String} and equal to one of the allowed values\n\n [ 'none', 'silent', 'info', 'debug', 'trace', 'error', 'warning', 'warn' ]\n\n (https://webpack.js.org/configuration/dev-server/#devserverclientloglevel)", | ||
"client": "should be {Object} (https://webpack.js.org/configuration/dev-server/#devserverclient)", | ||
"compress": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devservercompress)", | ||
"contentBase": "should be {Number|String|Array} (https://webpack.js.org/configuration/dev-server/#devservercontentbase)", | ||
"disableHostCheck": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverdisablehostcheck)", | ||
"features": "should be {Array}", | ||
"filename": "should be {String|RegExp|Function} (https://webpack.js.org/configuration/dev-server/#devserverfilename-)", | ||
"fs": "should be {Object} (https://github.com/webpack/webpack-dev-middleware#fs)", | ||
"headers": "should be {Object} (https://webpack.js.org/configuration/dev-server/#devserverheaders-)", | ||
"dev": "should be {Object} (https://webpack.js.org/configuration/dev-server/#devserverdev-)", | ||
"firewall": "should be {Boolean|Array} (https://webpack.js.org/configuration/dev-server/#devserverfirewall)", | ||
"headers": "should be {Object} (https://webpack.js.org/configuration/dev-server/#devserverheaders)", | ||
"historyApiFallback": "should be {Boolean|Object} (https://webpack.js.org/configuration/dev-server/#devserverhistoryapifallback)", | ||
"host": "should be {String|Null} (https://webpack.js.org/configuration/dev-server/#devserverhost)", | ||
"hot": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverhot)", | ||
"hotOnly": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverhotonly)", | ||
"hot": "should be {Boolean|String} (https://webpack.js.org/configuration/dev-server/#devserverhot)", | ||
"http2": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverhttp2)", | ||
"https": "should be {Object|Boolean} (https://webpack.js.org/configuration/dev-server/#devserverhttps)", | ||
"index": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverindex)", | ||
"injectClient": "should be {Boolean|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjectclient)", | ||
"injectHot": "should be {Boolean|Function} (https://webpack.js.org/configuration/dev-server/#devserverinjecthot)", | ||
"inline": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverinline)", | ||
"key": "should be {String|Buffer}", | ||
"lazy": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverlazy-)", | ||
"liveReload": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverlivereload-)", | ||
"log": "should be {Function}", | ||
"logLevel": "should be {String} and equal to one of the allowed values\n\n [ 'info', 'warn', 'error', 'debug', 'trace', 'silent' ]\n\n (https://github.com/webpack/webpack-dev-middleware#loglevel)", | ||
"logTime": "should be {Boolean} (https://github.com/webpack/webpack-dev-middleware#logtime)", | ||
"mimeTypes": "should be {Object} (https://webpack.js.org/configuration/dev-server/#devservermimetypes-)", | ||
"noInfo": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devservernoinfo-)", | ||
"liveReload": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverlivereload)", | ||
"onAfterSetupMiddleware": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserverafter)", | ||
"onBeforeSetupMiddleware": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserverbefore)", | ||
"onListening": "should be {Function} (https://webpack.js.org/configuration/dev-server/#onlistening)", | ||
@@ -478,29 +416,10 @@ "open": "should be {String|Boolean|Object} (https://webpack.js.org/configuration/dev-server/#devserveropen)", | ||
"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)", | ||
"port": "should be {Number|String|Null} (https://webpack.js.org/configuration/dev-server/#devserverport)", | ||
"profile": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverprofile)", | ||
"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)", | ||
"publicPath": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserverpublicpath-)", | ||
"quiet": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverquiet-)", | ||
"reporter": "should be {Function} (https://github.com/webpack/webpack-dev-middleware#reporter)", | ||
"requestCert": "should be {Boolean}", | ||
"contentBasePublicPath": "should be {String|Array} (https://webpack.js.org/configuration/dev-server/#devservercontentbasepublicpath)", | ||
"serveIndex": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverserveindex)", | ||
"serverSideRender": "should be {Boolean} (https://github.com/webpack/webpack-dev-middleware#serversiderender)", | ||
"setup": "should be {Function} (https://webpack.js.org/configuration/dev-server/#devserversetup)", | ||
"sockHost": "should be {String|Null} (https://webpack.js.org/configuration/dev-server/#devserversockhost)", | ||
"sockPath": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserversockpath)", | ||
"sockPort": "should be {Number|String|Null} (https://webpack.js.org/configuration/dev-server/#devserversockport)", | ||
"socket": "should be {String} (https://webpack.js.org/configuration/dev-server/#devserversocket)", | ||
"staticOptions": "should be {Object} (https://webpack.js.org/configuration/dev-server/#devserverstaticoptions)", | ||
"stats": "should be {Object|Boolean} (https://webpack.js.org/configuration/dev-server/#devserverstats-)", | ||
"setupExitSignals": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserversetupexitsignals)", | ||
"static": "should be {Boolean|String|Object|Array} (https://webpack.js.org/configuration/dev-server/#devserverstatic)", | ||
"stdin": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverstdin)", | ||
"transportMode": "should be {String|Object} (https://webpack.js.org/configuration/dev-server/#devservertransportmode)", | ||
"useLocalIp": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserveruselocalip)", | ||
"warn": "should be {Function}", | ||
"watchContentBase": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserverwatchcontentbase)", | ||
"watchOptions": "should be {Object} (https://webpack.js.org/configuration/dev-server/#devserverwatchoptions-)", | ||
"writeToDisk": "should be {Boolean|Function} (https://webpack.js.org/configuration/dev-server/#devserverwritetodisk-)" | ||
"useLocalIp": "should be {Boolean} (https://webpack.js.org/configuration/dev-server/#devserveruselocalip)" | ||
} | ||
@@ -507,0 +426,0 @@ }, |
'use strict'; | ||
/* eslint-disable | ||
no-shadow, | ||
no-undefined, | ||
func-names | ||
*/ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const tls = require('tls'); | ||
const url = require('url'); | ||
@@ -15,7 +9,6 @@ const http = require('http'); | ||
const ip = require('ip'); | ||
const semver = require('semver'); | ||
const killable = require('killable'); | ||
const chokidar = require('chokidar'); | ||
const express = require('express'); | ||
const httpProxyMiddleware = require('http-proxy-middleware'); | ||
const { createProxyMiddleware } = require('http-proxy-middleware'); | ||
const historyApiFallback = require('connect-history-api-fallback'); | ||
@@ -26,7 +19,7 @@ const compress = require('compression'); | ||
const webpackDevMiddleware = require('webpack-dev-middleware'); | ||
const validateOptions = require('schema-utils'); | ||
const isAbsoluteUrl = require('is-absolute-url'); | ||
const getFilenameFromUrl = require('webpack-dev-middleware/dist/utils/getFilenameFromUrl') | ||
.default; | ||
const { validate } = require('schema-utils'); | ||
const normalizeOptions = require('./utils/normalizeOptions'); | ||
const updateCompiler = require('./utils/updateCompiler'); | ||
const createLogger = require('./utils/createLogger'); | ||
const getCertificate = require('./utils/getCertificate'); | ||
@@ -38,13 +31,9 @@ const status = require('./utils/status'); | ||
const getSocketServerImplementation = require('./utils/getSocketServerImplementation'); | ||
const getCompilerConfigArray = require('./utils/getCompilerConfigArray'); | ||
const getStatsOption = require('./utils/getStatsOption'); | ||
const getColorsOption = require('./utils/getColorsOption'); | ||
const setupExitSignals = require('./utils/setupExitSignals'); | ||
const findPort = require('./utils/findPort'); | ||
const schema = require('./options.json'); | ||
// Workaround for node ^8.6.0, ^9.0.0 | ||
// DEFAULT_ECDH_CURVE is default to prime256v1 in these version | ||
// breaking connection when certificate is not signed with prime256v1 | ||
// change it to auto allows OpenSSL to select the curve automatically | ||
// See https://github.com/nodejs/node/issues/16196 for more information | ||
if (semver.satisfies(process.version, '8.6.0 - 9')) { | ||
tls.DEFAULT_ECDH_CURVE = 'auto'; | ||
} | ||
if (!process.env.WEBPACK_DEV_SERVER) { | ||
@@ -55,65 +44,25 @@ process.env.WEBPACK_DEV_SERVER = true; | ||
class Server { | ||
constructor(compiler, options = {}, _log) { | ||
if (options.lazy && !options.filename) { | ||
throw new Error("'filename' option must be set in lazy mode."); | ||
} | ||
constructor(compiler, options = {}) { | ||
validate(schema, options, 'webpack Dev Server'); | ||
validateOptions(schema, options, 'webpack Dev Server'); | ||
this.compiler = compiler; | ||
this.options = options; | ||
this.logger = this.compiler.getInfrastructureLogger('webpack-dev-server'); | ||
this.sockets = []; | ||
this.contentBaseWatchers = []; | ||
// Keep track of websocket proxies for external websocket upgrade. | ||
this.websocketProxies = []; | ||
// this value of ws can be overwritten for tests | ||
this.wsHeartbeatInterval = 30000; | ||
this.log = _log || createLogger(options); | ||
if (this.options.transportMode !== undefined) { | ||
this.log.warn( | ||
'transportMode is an experimental option, meaning its usage could potentially change without warning' | ||
); | ||
} | ||
normalizeOptions(this.compiler, this.options); | ||
updateCompiler(this.compiler, this.options); | ||
this.heartbeatInterval = 30000; | ||
// this.SocketServerImplementation is a class, so it must be instantiated before use | ||
this.socketServerImplementation = getSocketServerImplementation( | ||
this.SocketServerImplementation = getSocketServerImplementation( | ||
this.options | ||
); | ||
this.originalStats = | ||
this.options.stats && Object.keys(this.options.stats).length | ||
? this.options.stats | ||
: {}; | ||
this.sockets = []; | ||
this.contentBaseWatchers = []; | ||
// TODO this.<property> is deprecated (remove them in next major release.) in favor this.options.<property> | ||
this.hot = this.options.hot || this.options.hotOnly; | ||
this.headers = this.options.headers; | ||
this.progress = this.options.progress; | ||
this.serveIndex = this.options.serveIndex; | ||
this.clientOverlay = this.options.overlay; | ||
this.clientLogLevel = this.options.clientLogLevel; | ||
this.publicHost = this.options.public; | ||
this.allowedHosts = this.options.allowedHosts; | ||
this.disableHostCheck = !!this.options.disableHostCheck; | ||
this.watchOptions = options.watchOptions || {}; | ||
// Replace leading and trailing slashes to normalize path | ||
this.sockPath = `/${ | ||
this.options.sockPath | ||
? this.options.sockPath.replace(/^\/|\/$/g, '') | ||
: 'sockjs-node' | ||
}`; | ||
if (this.progress) { | ||
if (this.options.client.progress) { | ||
this.setupProgressPlugin(); | ||
} | ||
this.setupHooks(); | ||
@@ -123,9 +72,2 @@ this.setupApp(); | ||
this.setupDevMiddleware(); | ||
// set express routes | ||
routes(this); | ||
// Keep track of websocket proxies for external websocket upgrade. | ||
this.websocketProxies = []; | ||
this.setupFeatures(); | ||
@@ -135,7 +77,11 @@ this.setupHttps(); | ||
routes(this); | ||
killable(this.listeningApp); | ||
// Proxy websockets without the initial http request | ||
setupExitSignals(this); | ||
// Proxy WebSocket without the initial http request | ||
// https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade | ||
this.websocketProxies.forEach(function(wsProxy) { | ||
// eslint-disable-next-line func-names | ||
this.websocketProxies.forEach(function (wsProxy) { | ||
this.listeningApp.on('upgrade', wsProxy.upgrade); | ||
@@ -146,8 +92,2 @@ }, this); | ||
setupProgressPlugin() { | ||
// for CLI output | ||
new webpack.ProgressPlugin({ | ||
profile: !!this.options.profile, | ||
}).apply(this.compiler); | ||
// for browser console output | ||
new webpack.ProgressPlugin((percent, msg, addInfo) => { | ||
@@ -190,4 +130,4 @@ percent = Math.floor(percent * 100); | ||
done.tap('webpack-dev-server', (stats) => { | ||
this._sendStats(this.sockets, this.getStats(stats)); | ||
this._stats = stats; | ||
this.sendStats(this.sockets, this.getStats(stats)); | ||
this.stats = stats; | ||
}); | ||
@@ -215,6 +155,3 @@ }; | ||
// middleware for serving webpack bundle | ||
this.middleware = webpackDevMiddleware( | ||
this.compiler, | ||
Object.assign({}, this.options, { logLevel: this.log.options.level }) | ||
); | ||
this.middleware = webpackDevMiddleware(this.compiler, this.options.dev); | ||
} | ||
@@ -258,4 +195,23 @@ | ||
proxyOptions.logLevel = proxyOptions.logLevel || 'warn'; | ||
const getLogLevelForProxy = (level) => { | ||
if (level === 'none') { | ||
return 'silent'; | ||
} | ||
if (level === 'log') { | ||
return 'info'; | ||
} | ||
if (level === 'verbose') { | ||
return 'debug'; | ||
} | ||
return level; | ||
}; | ||
proxyOptions.logLevel = getLogLevelForProxy( | ||
this.compiler.options.infrastructureLogging.level | ||
); | ||
proxyOptions.logProvider = () => this.logger; | ||
return proxyOptions; | ||
@@ -272,3 +228,3 @@ }); | ||
if (proxyConfig.target) { | ||
return httpProxyMiddleware(context, proxyConfig); | ||
return createProxyMiddleware(context, proxyConfig); | ||
} | ||
@@ -306,5 +262,5 @@ }; | ||
const handle = (req, res, next) => { | ||
const handle = async (req, res, next) => { | ||
if (typeof proxyConfigOrCallback === 'function') { | ||
const newProxyConfig = proxyConfigOrCallback(); | ||
const newProxyConfig = proxyConfigOrCallback(req, res, next); | ||
@@ -322,3 +278,3 @@ if (newProxyConfig !== proxyConfig) { | ||
const bypassUrl = isByPassFuncDefined | ||
? proxyConfig.bypass(req, res, proxyConfig) | ||
? await proxyConfig.bypass(req, res, proxyConfig) | ||
: null; | ||
@@ -358,113 +314,43 @@ | ||
setupStaticFeature() { | ||
const contentBase = this.options.contentBase; | ||
const contentBasePublicPath = this.options.contentBasePublicPath; | ||
if (Array.isArray(contentBase)) { | ||
contentBase.forEach((item, index) => { | ||
let publicPath = contentBasePublicPath; | ||
if ( | ||
Array.isArray(contentBasePublicPath) && | ||
contentBasePublicPath[index] | ||
) { | ||
publicPath = contentBasePublicPath[index] || contentBasePublicPath[0]; | ||
} | ||
this.app.use(publicPath, express.static(item)); | ||
this.options.static.forEach((staticOption) => { | ||
staticOption.publicPath.forEach((publicPath) => { | ||
this.app.use( | ||
publicPath, | ||
express.static(staticOption.directory, staticOption.staticOptions) | ||
); | ||
}); | ||
} else if (isAbsoluteUrl(String(contentBase))) { | ||
this.log.warn( | ||
'Using a URL as contentBase is deprecated and will be removed in the next major version. Please use the proxy option instead.' | ||
); | ||
this.log.warn( | ||
'proxy: {\n\t"*": "<your current contentBase configuration>"\n}' | ||
); | ||
// Redirect every request to contentBase | ||
this.app.get('*', (req, res) => { | ||
res.writeHead(302, { | ||
Location: contentBase + req.path + (req._parsedUrl.search || ''), | ||
}); | ||
res.end(); | ||
}); | ||
} else if (typeof contentBase === 'number') { | ||
this.log.warn( | ||
'Using a number as contentBase is deprecated and will be removed in the next major version. Please use the proxy option instead.' | ||
); | ||
this.log.warn( | ||
'proxy: {\n\t"*": "//localhost:<your current contentBase configuration>"\n}' | ||
); | ||
// Redirect every request to the port contentBase | ||
this.app.get('*', (req, res) => { | ||
res.writeHead(302, { | ||
Location: `//localhost:${contentBase}${req.path}${req._parsedUrl | ||
.search || ''}`, | ||
}); | ||
res.end(); | ||
}); | ||
} else { | ||
// route content request | ||
this.app.use( | ||
contentBasePublicPath, | ||
express.static(contentBase, this.options.staticOptions) | ||
); | ||
} | ||
}); | ||
} | ||
setupServeIndexFeature() { | ||
const contentBase = this.options.contentBase; | ||
const contentBasePublicPath = this.options.contentBasePublicPath; | ||
setupStaticServeIndexFeature() { | ||
this.options.static.forEach((staticOption) => { | ||
staticOption.publicPath.forEach((publicPath) => { | ||
if (staticOption.serveIndex) { | ||
this.app.use(publicPath, (req, res, next) => { | ||
// serve-index doesn't fallthrough non-get/head request to next middleware | ||
if (req.method !== 'GET' && req.method !== 'HEAD') { | ||
return next(); | ||
} | ||
if (Array.isArray(contentBase)) { | ||
contentBase.forEach((item) => { | ||
this.app.use(contentBasePublicPath, (req, res, next) => { | ||
// serve-index doesn't fallthrough non-get/head request to next middleware | ||
if (req.method !== 'GET' && req.method !== 'HEAD') { | ||
return next(); | ||
} | ||
serveIndex(item, { icons: true })(req, res, next); | ||
}); | ||
}); | ||
} else if ( | ||
typeof contentBase !== 'number' && | ||
!isAbsoluteUrl(String(contentBase)) | ||
) { | ||
this.app.use(contentBasePublicPath, (req, res, next) => { | ||
// serve-index doesn't fallthrough non-get/head request to next middleware | ||
if (req.method !== 'GET' && req.method !== 'HEAD') { | ||
return next(); | ||
serveIndex(staticOption.directory, staticOption.serveIndex)( | ||
req, | ||
res, | ||
next | ||
); | ||
}); | ||
} | ||
serveIndex(contentBase, { icons: true })(req, res, next); | ||
}); | ||
} | ||
}); | ||
} | ||
setupWatchStaticFeature() { | ||
const contentBase = this.options.contentBase; | ||
if (isAbsoluteUrl(String(contentBase)) || typeof contentBase === 'number') { | ||
throw new Error('Watching remote files is not supported.'); | ||
} else if (Array.isArray(contentBase)) { | ||
contentBase.forEach((item) => { | ||
if (isAbsoluteUrl(String(item)) || typeof item === 'number') { | ||
throw new Error('Watching remote files is not supported.'); | ||
} | ||
this._watch(item); | ||
}); | ||
} else { | ||
this._watch(contentBase); | ||
} | ||
setupStaticWatchFeature() { | ||
this.options.static.forEach((staticOption) => { | ||
if (staticOption.watch) { | ||
this.watchFiles(staticOption.directory, staticOption.watch); | ||
} | ||
}); | ||
} | ||
setupBeforeFeature() { | ||
// Todo rename onBeforeSetupMiddleware in next major release | ||
// Todo pass only `this` argument | ||
this.options.before(this.app, this, this.compiler); | ||
setupOnBeforeSetupMiddlewareFeature() { | ||
this.options.onBeforeSetupMiddleware(this); | ||
} | ||
@@ -476,6 +362,4 @@ | ||
setupAfterFeature() { | ||
// Todo rename onAfterSetupMiddleware in next major release | ||
// Todo pass only `this` argument | ||
this.options.after(this.app, this, this.compiler); | ||
setupOnAfterSetupMiddlewareFeature() { | ||
this.options.onAfterSetupMiddleware(this); | ||
} | ||
@@ -491,10 +375,2 @@ | ||
setupSetupFeature() { | ||
this.log.warn( | ||
'The `setup` option is deprecated and will be removed in v4. Please update your config to use `before`' | ||
); | ||
this.options.setup(this.app, this); | ||
} | ||
setupFeatures() { | ||
@@ -517,19 +393,21 @@ const features = { | ||
}, | ||
// Todo rename to `static` in future major release | ||
contentBaseFiles: () => { | ||
static: () => { | ||
this.setupStaticFeature(); | ||
}, | ||
// Todo rename to `serveIndex` in future major release | ||
contentBaseIndex: () => { | ||
this.setupServeIndexFeature(); | ||
staticServeIndex: () => { | ||
this.setupStaticServeIndexFeature(); | ||
}, | ||
// Todo rename to `watchStatic` in future major release | ||
watchContentBase: () => { | ||
this.setupWatchStaticFeature(); | ||
staticWatch: () => { | ||
this.setupStaticWatchFeature(); | ||
}, | ||
before: () => { | ||
if (typeof this.options.before === 'function') { | ||
this.setupBeforeFeature(); | ||
onBeforeSetupMiddleware: () => { | ||
if (typeof this.options.onBeforeSetupMiddleware === 'function') { | ||
this.setupOnBeforeSetupMiddlewareFeature(); | ||
} | ||
}, | ||
onAfterSetupMiddleware: () => { | ||
if (typeof this.options.onAfterSetupMiddleware === 'function') { | ||
this.setupOnAfterSetupMiddlewareFeature(); | ||
} | ||
}, | ||
middleware: () => { | ||
@@ -540,7 +418,2 @@ // include our middleware to ensure | ||
}, | ||
after: () => { | ||
if (typeof this.options.after === 'function') { | ||
this.setupAfterFeature(); | ||
} | ||
}, | ||
headers: () => { | ||
@@ -552,7 +425,2 @@ this.setupHeadersFeature(); | ||
}, | ||
setup: () => { | ||
if (typeof this.options.setup === 'function') { | ||
this.setupSetupFeature(); | ||
} | ||
}, | ||
}; | ||
@@ -567,4 +435,8 @@ | ||
runnableFeatures.push('setup', 'before', 'headers', 'middleware'); | ||
if (this.options.onBeforeSetupMiddleware) { | ||
runnableFeatures.push('onBeforeSetupMiddleware'); | ||
} | ||
runnableFeatures.push('headers', 'middleware'); | ||
if (this.options.proxy) { | ||
@@ -574,4 +446,4 @@ runnableFeatures.push('proxy', 'middleware'); | ||
if (this.options.contentBase !== false) { | ||
runnableFeatures.push('contentBaseFiles'); | ||
if (this.options.static) { | ||
runnableFeatures.push('static'); | ||
} | ||
@@ -582,25 +454,18 @@ | ||
if (this.options.contentBase !== false) { | ||
runnableFeatures.push('contentBaseFiles'); | ||
if (this.options.static) { | ||
runnableFeatures.push('static'); | ||
} | ||
} | ||
// checking if it's set to true or not set (Default : undefined => true) | ||
this.serveIndex = this.serveIndex || this.serveIndex === undefined; | ||
if (this.options.contentBase && this.serveIndex) { | ||
runnableFeatures.push('contentBaseIndex'); | ||
if (this.options.static) { | ||
runnableFeatures.push('staticServeIndex', 'staticWatch'); | ||
} | ||
if (this.options.watchContentBase) { | ||
runnableFeatures.push('watchContentBase'); | ||
} | ||
runnableFeatures.push('magicHtml'); | ||
if (this.options.after) { | ||
runnableFeatures.push('after'); | ||
if (this.options.onAfterSetupMiddleware) { | ||
runnableFeatures.push('onAfterSetupMiddleware'); | ||
} | ||
(this.options.features || runnableFeatures).forEach((feature) => { | ||
runnableFeatures.forEach((feature) => { | ||
features[feature](); | ||
@@ -612,19 +477,12 @@ }); | ||
// if the user enables http2, we can safely enable https | ||
if (this.options.http2 && !this.options.https) { | ||
this.options.https = true; | ||
if ( | ||
(this.options.http2 && !this.options.https) || | ||
this.options.https === true | ||
) { | ||
this.options.https = { | ||
requestCert: false, | ||
}; | ||
} | ||
if (this.options.https) { | ||
// for keep supporting CLI parameters | ||
if (typeof this.options.https === 'boolean') { | ||
this.options.https = { | ||
ca: this.options.ca, | ||
pfx: this.options.pfx, | ||
key: this.options.key, | ||
cert: this.options.cert, | ||
passphrase: this.options.pfxPassphrase, | ||
requestCert: this.options.requestCert || false, | ||
}; | ||
} | ||
for (const property of ['ca', 'pfx', 'key', 'cert']) { | ||
@@ -653,3 +511,3 @@ const value = this.options.https[property]; | ||
if (!this.options.https.key || !this.options.https.cert) { | ||
fakeCert = getCertificate(this.log); | ||
fakeCert = getCertificate(this.logger); | ||
} | ||
@@ -659,19 +517,2 @@ | ||
this.options.https.cert = this.options.https.cert || fakeCert; | ||
// note that options.spdy never existed. The user was able | ||
// to set options.https.spdy before, though it was not in the | ||
// docs. Keep options.https.spdy if the user sets it for | ||
// backwards compatibility, but log a deprecation warning. | ||
if (this.options.https.spdy) { | ||
// for backwards compatibility: if options.https.spdy was passed in before, | ||
// it was not altered in any way | ||
this.log.warn( | ||
'Providing custom spdy server options is deprecated and will be removed in the next major version.' | ||
); | ||
} else { | ||
// if the normal https server gets this option, it will not affect it. | ||
this.options.https.spdy = { | ||
protocols: ['h2', 'http/1.1'], | ||
}; | ||
} | ||
} | ||
@@ -682,31 +523,15 @@ } | ||
if (this.options.https) { | ||
// Only prevent HTTP/2 if http2 is explicitly set to false | ||
const isHttp2 = this.options.http2 !== false; | ||
// `spdy` is effectively unmaintained, and as a consequence of an | ||
// implementation that extensively relies on Node’s non-public APIs, broken | ||
// on Node 10 and above. In those cases, only https will be used for now. | ||
// Once express supports Node's built-in HTTP/2 support, migrating over to | ||
// that should be the best way to go. | ||
// The relevant issues are: | ||
// - https://github.com/nodejs/node/issues/21665 | ||
// - https://github.com/webpack/webpack-dev-server/issues/1449 | ||
// - https://github.com/expressjs/express/issues/3388 | ||
if (semver.gte(process.version, '10.0.0') || !isHttp2) { | ||
if (this.options.http2) { | ||
// the user explicitly requested http2 but is not getting it because | ||
// of the node version. | ||
this.log.warn( | ||
'HTTP/2 is currently unsupported for Node 10.0.0 and above, but will be supported once Express supports it' | ||
); | ||
} | ||
this.listeningApp = https.createServer(this.options.https, this.app); | ||
} else { | ||
// The relevant issues are: | ||
// https://github.com/spdy-http2/node-spdy/issues/350 | ||
// https://github.com/webpack/webpack-dev-server/issues/1592 | ||
if (this.options.http2) { | ||
// TODO: we need to replace spdy with http2 which is an internal module | ||
this.listeningApp = require('spdy').createServer( | ||
this.options.https, | ||
{ | ||
...this.options.https, | ||
spdy: { | ||
protocols: ['h2', 'http/1.1'], | ||
}, | ||
}, | ||
this.app | ||
); | ||
} else { | ||
this.listeningApp = https.createServer(this.options.https, this.app); | ||
} | ||
@@ -718,3 +543,3 @@ } else { | ||
this.listeningApp.on('error', (err) => { | ||
this.log.error(err); | ||
throw err; | ||
}); | ||
@@ -724,4 +549,3 @@ } | ||
createSocketServer() { | ||
const SocketServerImplementation = this.socketServerImplementation; | ||
this.socketServer = new SocketServerImplementation(this); | ||
this.socketServer = new this.SocketServerImplementation(this); | ||
@@ -734,3 +558,3 @@ this.socketServer.onConnection((connection, headers) => { | ||
if (!headers) { | ||
this.log.warn( | ||
this.logger.warn( | ||
'transportMode.server implementation must pass headers to the callback of onConnection(f) ' + | ||
@@ -759,28 +583,27 @@ 'via f(connection, headers) in order for clients to pass a headers security check' | ||
if (this.clientLogLevel) { | ||
this.sockWrite([connection], 'log-level', this.clientLogLevel); | ||
if (this.options.client.logging) { | ||
this.sockWrite([connection], 'logging', this.options.client.logging); | ||
} | ||
if (this.hot) { | ||
if (this.options.hot === true || this.options.hot === 'only') { | ||
this.sockWrite([connection], 'hot'); | ||
} | ||
// TODO: change condition at major version | ||
if (this.options.liveReload !== false) { | ||
this.sockWrite([connection], 'liveReload', this.options.liveReload); | ||
if (this.options.liveReload) { | ||
this.sockWrite([connection], 'liveReload'); | ||
} | ||
if (this.progress) { | ||
this.sockWrite([connection], 'progress', this.progress); | ||
if (this.options.client.progress) { | ||
this.sockWrite([connection], 'progress', this.options.client.progress); | ||
} | ||
if (this.clientOverlay) { | ||
this.sockWrite([connection], 'overlay', this.clientOverlay); | ||
if (this.options.clientOverlay) { | ||
this.sockWrite([connection], 'overlay', this.options.clientOverlay); | ||
} | ||
if (!this._stats) { | ||
if (!this.stats) { | ||
return; | ||
} | ||
this._sendStats([connection], this.getStats(this._stats), true); | ||
this.sendStats([connection], this.getStats(this.stats), true); | ||
}); | ||
@@ -790,14 +613,9 @@ } | ||
showStatus() { | ||
const suffix = | ||
this.options.inline !== false || this.options.lazy === true | ||
? '/' | ||
: '/webpack-dev-server/'; | ||
const suffix = '/'; | ||
const uri = `${createDomain(this.options, this.listeningApp)}${suffix}`; | ||
status( | ||
uri, | ||
this.options, | ||
this.log, | ||
this.options.stats && this.options.stats.colors | ||
); | ||
const configArr = getCompilerConfigArray(this.compiler); | ||
const colors = getColorsOption(configArr); | ||
status(uri, this.options, this.logger, colors); | ||
} | ||
@@ -807,20 +625,40 @@ | ||
this.hostname = hostname; | ||
if (typeof port !== 'undefined' && port !== this.options.port) { | ||
this.logger.warn( | ||
'The port specified in options and the port passed as an argument is different.' | ||
); | ||
} | ||
return this.listeningApp.listen(port, hostname, (err) => { | ||
this.createSocketServer(); | ||
return ( | ||
findPort(port || this.options.port) | ||
// eslint-disable-next-line no-shadow | ||
.then((port) => { | ||
this.port = port; | ||
if (this.options.bonjour) { | ||
runBonjour(this.options); | ||
} | ||
return this.listeningApp.listen(port, hostname, (err) => { | ||
if (this.options.hot || this.options.liveReload) { | ||
this.createSocketServer(); | ||
} | ||
this.showStatus(); | ||
if (this.options.bonjour) { | ||
runBonjour(this.options); | ||
} | ||
if (fn) { | ||
fn.call(this.listeningApp, err); | ||
} | ||
this.showStatus(); | ||
if (typeof this.options.onListening === 'function') { | ||
this.options.onListening(this); | ||
} | ||
}); | ||
if (fn) { | ||
fn.call(this.listeningApp, err); | ||
} | ||
if (typeof this.options.onListening === 'function') { | ||
this.options.onListening(this); | ||
} | ||
}); | ||
}) | ||
.catch((err) => { | ||
if (fn) { | ||
fn.call(this.listeningApp, err); | ||
} | ||
}) | ||
); | ||
} | ||
@@ -835,10 +673,12 @@ | ||
this.contentBaseWatchers.forEach((watcher) => { | ||
watcher.close(); | ||
}); | ||
const prom = Promise.all( | ||
this.contentBaseWatchers.map((watcher) => watcher.close()) | ||
); | ||
this.contentBaseWatchers = []; | ||
this.listeningApp.kill(() => { | ||
this.middleware.close(cb); | ||
// watchers must be closed before closing middleware | ||
prom.then(() => { | ||
this.middleware.close(cb); | ||
}); | ||
}); | ||
@@ -861,4 +701,6 @@ } | ||
if (this.originalStats.warningsFilter) { | ||
stats.warningsFilter = this.originalStats.warningsFilter; | ||
const configArr = getCompilerConfigArray(this.compiler); | ||
const statsOption = getStatsOption(configArr); | ||
if (typeof statsOption === 'object' && statsOption.warningsFilter) { | ||
stats.warningsFilter = statsOption.warningsFilter; | ||
} | ||
@@ -870,3 +712,3 @@ | ||
use() { | ||
// eslint-disable-next-line | ||
// eslint-disable-next-line prefer-spread | ||
this.app.use.apply(this.app, arguments); | ||
@@ -876,6 +718,6 @@ } | ||
setContentHeaders(req, res, next) { | ||
if (this.headers) { | ||
// eslint-disable-next-line | ||
for (const name in this.headers) { | ||
res.setHeader(name, this.headers[name]); | ||
if (this.options.headers) { | ||
// eslint-disable-next-line guard-for-in | ||
for (const name in this.options.headers) { | ||
res.setHeader(name, this.options.headers[name]); | ||
} | ||
@@ -896,4 +738,5 @@ } | ||
checkHeaders(headers, headerToCheck) { | ||
// allow user to opt-out this security check, at own risk | ||
if (this.disableHostCheck) { | ||
// allow user to opt out of this security check, at their own risk | ||
// by explicitly disabling firewall | ||
if (!this.options.firewall) { | ||
return true; | ||
@@ -938,7 +781,10 @@ } | ||
} | ||
const allowedHosts = this.options.firewall; | ||
// always allow localhost host, for convenience | ||
// allow if hostname is in allowedHosts | ||
if (this.allowedHosts && this.allowedHosts.length) { | ||
for (let hostIdx = 0; hostIdx < this.allowedHosts.length; hostIdx++) { | ||
const allowedHost = this.allowedHosts[hostIdx]; | ||
if (Array.isArray(allowedHosts) && allowedHosts.length) { | ||
for (let hostIdx = 0; hostIdx < allowedHosts.length; hostIdx++) { | ||
const allowedHost = allowedHosts[hostIdx]; | ||
@@ -965,6 +811,8 @@ if (allowedHost === hostname) { | ||
// also allow public hostname if provided | ||
if (typeof this.publicHost === 'string') { | ||
const idxPublic = this.publicHost.indexOf(':'); | ||
if (typeof this.options.public === 'string') { | ||
const idxPublic = this.options.public.indexOf(':'); | ||
const publicHostname = | ||
idxPublic >= 0 ? this.publicHost.substr(0, idxPublic) : this.publicHost; | ||
idxPublic >= 0 | ||
? this.options.public.substr(0, idxPublic) | ||
: this.options.public; | ||
@@ -980,3 +828,2 @@ if (hostname === publicHostname) { | ||
// eslint-disable-next-line | ||
sockWrite(sockets, type, data) { | ||
@@ -992,4 +839,8 @@ sockets.forEach((socket) => { | ||
try { | ||
const isFile = this.middleware.fileSystem | ||
.statSync(this.middleware.getFilenameFromUrl(`${_path}.js`)) | ||
const filename = getFilenameFromUrl( | ||
this.middleware.context, | ||
`${_path}.js` | ||
); | ||
const isFile = this.middleware.context.outputFileSystem | ||
.statSync(filename) | ||
.isFile(); | ||
@@ -1010,3 +861,3 @@ | ||
// send stats to a socket or multiple sockets | ||
_sendStats(sockets, stats, force) { | ||
sendStats(sockets, stats, force) { | ||
const shouldEmit = | ||
@@ -1034,13 +885,15 @@ !force && | ||
_watch(watchPath) { | ||
watchFiles(watchPath, watchOptions) { | ||
// duplicate the same massaging of options that watchpack performs | ||
// https://github.com/webpack/watchpack/blob/master/lib/DirectoryWatcher.js#L49 | ||
// this isn't an elegant solution, but we'll improve it in the future | ||
const usePolling = this.watchOptions.poll ? true : undefined; | ||
// eslint-disable-next-line no-undefined | ||
const usePolling = watchOptions.poll ? true : undefined; | ||
const interval = | ||
typeof this.watchOptions.poll === 'number' | ||
? this.watchOptions.poll | ||
: undefined; | ||
typeof watchOptions.poll === 'number' | ||
? watchOptions.poll | ||
: // eslint-disable-next-line no-undefined | ||
undefined; | ||
const watchOptions = { | ||
const finalWatchOptions = { | ||
ignoreInitial: true, | ||
@@ -1052,3 +905,3 @@ persistent: true, | ||
ignorePermissionErrors: true, | ||
ignored: this.watchOptions.ignored, | ||
ignored: watchOptions.ignored, | ||
usePolling, | ||
@@ -1058,5 +911,5 @@ interval, | ||
const watcher = chokidar.watch(watchPath, watchOptions); | ||
const watcher = chokidar.watch(watchPath, finalWatchOptions); | ||
// disabling refreshing on changing the content | ||
if (this.options.liveReload !== false) { | ||
if (this.options.liveReload) { | ||
watcher.on('change', () => { | ||
@@ -1076,7 +929,2 @@ this.sockWrite(this.sockets, 'content-changed'); | ||
// Export this logic, | ||
// so that other implementations, | ||
// like task-runners can use it | ||
Server.addDevServerEntrypoints = require('./utils/addEntries'); | ||
module.exports = Server; |
'use strict'; | ||
/* eslint-disable | ||
class-methods-use-this, | ||
func-names | ||
class-methods-use-this | ||
*/ | ||
@@ -16,3 +15,4 @@ const sockjs = require('sockjs'); | ||
const decorateConnection = SockjsSession.prototype.decorateConnection; | ||
SockjsSession.prototype.decorateConnection = function(req) { | ||
// eslint-disable-next-line func-names | ||
SockjsSession.prototype.decorateConnection = function (req) { | ||
decorateConnection.call(this, req); | ||
@@ -30,15 +30,20 @@ const connection = this.connection; | ||
module.exports = class SockJSServer extends BaseServer { | ||
module.exports = class SockJSServer extends ( | ||
BaseServer | ||
) { | ||
// options has: error (function), debug (function), server (http/s server), path (string) | ||
constructor(server) { | ||
super(server); | ||
this.socket = sockjs.createServer({ | ||
// Use provided up-to-date sockjs-client | ||
sockjs_url: '/__webpack_dev_server__/sockjs.bundle.js', | ||
// Limit useless logs | ||
// Default logger is very annoy. Limit useless logs. | ||
log: (severity, line) => { | ||
if (severity === 'error') { | ||
this.server.log.error(line); | ||
this.server.logger.error(line); | ||
} else if (severity === 'info') { | ||
this.server.logger.log(line); | ||
} else { | ||
this.server.log.debug(line); | ||
this.server.logger.debug(line); | ||
} | ||
@@ -49,3 +54,3 @@ }, | ||
this.socket.installHandlers(this.server.listeningApp, { | ||
prefix: this.server.sockPath, | ||
prefix: this.server.options.client.path, | ||
}); | ||
@@ -52,0 +57,0 @@ } |
@@ -9,8 +9,11 @@ 'use strict'; | ||
module.exports = class WebsocketServer extends BaseServer { | ||
module.exports = class WebsocketServer extends ( | ||
BaseServer | ||
) { | ||
constructor(server) { | ||
super(server); | ||
this.wsServer = new ws.Server({ | ||
noServer: true, | ||
path: this.server.sockPath, | ||
path: this.server.options.client.path, | ||
}); | ||
@@ -29,3 +32,3 @@ | ||
this.wsServer.on('error', (err) => { | ||
this.server.log.error(err.message); | ||
this.server.logger.error(err.message); | ||
}); | ||
@@ -44,3 +47,3 @@ | ||
}); | ||
}, this.server.heartbeatInterval); | ||
}, this.server.wsHeartbeatInterval); | ||
} | ||
@@ -47,0 +50,0 @@ |
@@ -8,8 +8,13 @@ 'use strict'; | ||
const protocol = options.https ? 'https' : 'http'; | ||
const hostname = options.useLocalIp | ||
? ip.v4.sync() || 'localhost' | ||
: options.host || 'localhost'; | ||
// eslint-disable-next-line no-nested-ternary | ||
const port = options.socket ? 0 : server ? server.address().port : 0; | ||
// use location hostname and port by default in createSocketUrl | ||
// ipv6 detection is not required as 0.0.0.0 is just used as a placeholder | ||
let hostname; | ||
if (options.useLocalIp) { | ||
hostname = ip.v4.sync() || '0.0.0.0'; | ||
} else if (server) { | ||
hostname = server.address().address; | ||
} else { | ||
hostname = '0.0.0.0'; | ||
} | ||
const port = server ? server.address().port : 0; | ||
// use explicitly defined public url | ||
@@ -16,0 +21,0 @@ // (prefix with protocol if not explicitly given) |
@@ -5,3 +5,5 @@ 'use strict'; | ||
const fs = require('fs'); | ||
const os = require('os'); | ||
const del = require('del'); | ||
const findCacheDir = require('find-cache-dir'); | ||
const createCertificate = require('./createCertificate'); | ||
@@ -12,3 +14,5 @@ | ||
// Cycle certs every 24 hours | ||
const certificatePath = path.join(__dirname, '../../ssl/server.pem'); | ||
const certificateDir = | ||
findCacheDir({ name: 'webpack-dev-server' }) || os.tmpdir(); | ||
const certificatePath = path.join(certificateDir, 'server.pem'); | ||
@@ -39,2 +43,3 @@ let certificateExists = fs.existsSync(certificatePath); | ||
fs.mkdirSync(certificateDir, { recursive: true }); | ||
fs.writeFileSync(certificatePath, pems.private + pems.cert, { | ||
@@ -41,0 +46,0 @@ encoding: 'utf8', |
@@ -33,3 +33,3 @@ 'use strict'; | ||
throw new Error( | ||
"transportMode.server must be a string denoting a default implementation (e.g. 'sockjs', 'ws'), a full path to " + | ||
"transportMode.server must be a string denoting a default implementation (e.g. 'ws', 'sockjs'), a full path to " + | ||
'a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer) ' + | ||
@@ -36,0 +36,0 @@ 'via require.resolve(...), or the class itself which extends BaseServer' |
'use strict'; | ||
/* eslint-disable | ||
no-undefined | ||
*/ | ||
const isAbsoluteUrl = require('is-absolute-url'); | ||
const getCompilerConfigArray = require('./getCompilerConfigArray'); | ||
function normalizeOptions(compiler, options) { | ||
// Setup default value | ||
options.contentBase = | ||
options.contentBase !== undefined ? options.contentBase : process.cwd(); | ||
// TODO: improve this to not use .find for compiler watchOptions | ||
const configArr = getCompilerConfigArray(compiler); | ||
const watchOptionsConfig = configArr.find( | ||
(config) => config.watch !== false && config.watchOptions | ||
); | ||
const watchOptions = watchOptionsConfig | ||
? watchOptionsConfig.watchOptions | ||
: {}; | ||
// Setup default value | ||
options.contentBasePublicPath = options.contentBasePublicPath || '/'; | ||
const defaultOptionsForStatic = { | ||
directory: process.cwd(), | ||
staticOptions: {}, | ||
publicPath: ['/'], | ||
serveIndex: { icons: true }, | ||
// Respect options from compiler watchOptions | ||
watch: watchOptions, | ||
}; | ||
if (typeof options.static === 'undefined') { | ||
options.static = [defaultOptionsForStatic]; | ||
} else if (typeof options.static === 'boolean') { | ||
options.static = options.static ? [defaultOptionsForStatic] : false; | ||
} else if (typeof options.static === 'string') { | ||
options.static = [ | ||
{ ...defaultOptionsForStatic, directory: options.static }, | ||
]; | ||
} else if (Array.isArray(options.static)) { | ||
options.static = options.static.map((item) => { | ||
if (typeof item === 'string') { | ||
return { ...defaultOptionsForStatic, directory: item }; | ||
} | ||
return { ...defaultOptionsForStatic, ...item }; | ||
}); | ||
} else { | ||
options.static = [{ ...defaultOptionsForStatic, ...options.static }]; | ||
} | ||
if (options.static) { | ||
options.static.forEach((staticOption) => { | ||
if (isAbsoluteUrl(staticOption.directory)) { | ||
throw new Error('Using a URL as static.directory is not supported'); | ||
} | ||
// ensure that publicPath is an array | ||
if (typeof staticOption.publicPath === 'string') { | ||
staticOption.publicPath = [staticOption.publicPath]; | ||
} | ||
// ensure that watch is an object if true | ||
if (staticOption.watch === true) { | ||
staticOption.watch = defaultOptionsForStatic.watch; | ||
} | ||
// ensure that serveIndex is an object if true | ||
if (staticOption.serveIndex === true) { | ||
staticOption.serveIndex = defaultOptionsForStatic.serveIndex; | ||
} | ||
}); | ||
} | ||
options.hot = | ||
typeof options.hot === 'boolean' || options.hot === 'only' | ||
? options.hot | ||
: true; | ||
options.liveReload = | ||
typeof options.liveReload !== 'undefined' ? options.liveReload : true; | ||
// normalize transportMode option | ||
if (options.transportMode === undefined) { | ||
if (typeof options.transportMode === 'undefined') { | ||
options.transportMode = { | ||
server: 'sockjs', | ||
client: 'sockjs', | ||
server: 'ws', | ||
client: 'ws', | ||
}; | ||
@@ -31,12 +91,23 @@ } else { | ||
default: | ||
options.transportMode.server = options.transportMode.server || 'sockjs'; | ||
options.transportMode.client = options.transportMode.client || 'sockjs'; | ||
options.transportMode.server = options.transportMode.server || 'ws'; | ||
options.transportMode.client = options.transportMode.client || 'ws'; | ||
} | ||
} | ||
if (!options.watchOptions) { | ||
options.watchOptions = {}; | ||
if (!options.client) { | ||
options.client = {}; | ||
} | ||
options.client.path = `/${ | ||
options.client.path ? options.client.path.replace(/^\/|\/$/g, '') : 'ws' | ||
}`; | ||
options.dev = options.dev || {}; | ||
if (typeof options.firewall === 'undefined') { | ||
// firewall is enabled by default | ||
options.firewall = true; | ||
} | ||
} | ||
module.exports = normalizeOptions; |
@@ -5,2 +5,3 @@ 'use strict'; | ||
const { join } = require('path'); | ||
const getPaths = require('webpack-dev-middleware/dist/utils/getPaths').default; | ||
@@ -12,14 +13,7 @@ const clientBasePath = join(__dirname, '..', '..', 'client'); | ||
const middleware = server.middleware; | ||
const options = server.options; | ||
app.get('/__webpack_dev_server__/live.bundle.js', (req, res) => { | ||
res.setHeader('Content-Type', 'application/javascript'); | ||
createReadStream(join(clientBasePath, 'live.bundle.js')).pipe(res); | ||
}); | ||
app.get('/__webpack_dev_server__/sockjs.bundle.js', (req, res) => { | ||
res.setHeader('Content-Type', 'application/javascript'); | ||
createReadStream(join(clientBasePath, 'sockjs.bundle.js')).pipe(res); | ||
createReadStream(join(clientBasePath, 'sockjs/sockjs.bundle.js')).pipe(res); | ||
}); | ||
@@ -30,3 +24,3 @@ | ||
createReadStream(join(clientBasePath, 'index.bundle.js')).pipe(res); | ||
createReadStream(join(clientBasePath, 'default/index.bundle.js')).pipe(res); | ||
}); | ||
@@ -39,8 +33,2 @@ | ||
app.get('/webpack-dev-server/*', (req, res) => { | ||
res.setHeader('Content-Type', 'text/html'); | ||
createReadStream(join(clientBasePath, 'live.html')).pipe(res); | ||
}); | ||
app.get('/webpack-dev-server', (req, res) => { | ||
@@ -53,6 +41,8 @@ res.setHeader('Content-Type', 'text/html'); | ||
const outputPath = middleware.getFilenameFromUrl(options.publicPath || '/'); | ||
const filesystem = middleware.fileSystem; | ||
const filesystem = middleware.context.outputFileSystem; | ||
const paths = getPaths(middleware.context); | ||
writeDirectory(options.publicPath || '/', outputPath); | ||
for (const { publicPath, outputPath } of paths) { | ||
writeDirectory(publicPath, outputPath); | ||
} | ||
@@ -62,2 +52,6 @@ res.end('</body></html>'); | ||
function writeDirectory(baseUrl, basePath) { | ||
if (baseUrl === 'auto') { | ||
baseUrl = ''; | ||
} | ||
const content = filesystem.readdirSync(basePath); | ||
@@ -67,6 +61,33 @@ | ||
content.forEach((item) => { | ||
const p = `${basePath}/${item}`; | ||
// sort file data so that files are listed before directories | ||
// this forces Windows to have consistent behavior, as it seems | ||
// to list directories first for the default memfs filesystem | ||
// of webpack-dev-middleware | ||
const fileData = content | ||
.map((item) => { | ||
const p = `${basePath}/${item}`; | ||
return { | ||
item, | ||
isFile: filesystem.statSync(p).isFile(), | ||
path: p, | ||
}; | ||
}) | ||
.sort((item1, item2) => { | ||
if (item1.isFile && !item2.isFile) { | ||
return -1; | ||
} else if (!item1.isFile && item2.isFile) { | ||
return 1; | ||
// sort alphabetically if both are files or directories | ||
} else if (item1.item < item2.item) { | ||
return -1; | ||
} else if (item2.item < item1.item) { | ||
return 1; | ||
} | ||
return 0; | ||
}); | ||
if (filesystem.statSync(p).isFile()) { | ||
fileData.forEach((data) => { | ||
const { item, isFile, path: p } = data; | ||
if (isFile) { | ||
res.write(`<li><a href="${baseUrl + item}">${item}</a></li>`); | ||
@@ -78,14 +99,3 @@ | ||
const magicHtmlHref = | ||
baseUrl.replace( | ||
// eslint-disable-next-line | ||
/(^(https?:\/\/[^\/]+)?\/)/, | ||
'$1webpack-dev-server/' | ||
) + html; | ||
res.write( | ||
`<li><a href="${containerHref}">${html}</a>` + | ||
` (magic html for ${item}) (<a href="${magicHtmlHref}">webpack-dev-server</a>)` + | ||
`</li>` | ||
); | ||
res.write(`<li><a href="${containerHref}">${html}</a>`); | ||
} | ||
@@ -92,0 +102,0 @@ } else { |
'use strict'; | ||
const open = require('opn'); | ||
const open = require('open'); | ||
const isAbsoluteUrl = require('is-absolute-url'); | ||
function runOpen(uri, options, log) { | ||
function runOpen(uri, options, logger) { | ||
// https://github.com/webpack/webpack-dev-server/issues/1990 | ||
@@ -29,3 +29,3 @@ let openOptions = { wait: false }; | ||
return open(pageUrl, openOptions).catch(() => { | ||
log.warn( | ||
logger.warn( | ||
`Unable to open "${pageUrl}" in browser${openOptionValue}. If you are running in a headless environment, please do not use the --open flag` | ||
@@ -32,0 +32,0 @@ ); |
@@ -5,18 +5,27 @@ 'use strict'; | ||
function setupExitSignals(serverData) { | ||
signals.forEach((signal) => { | ||
process.on(signal, () => { | ||
if (serverData && serverData.server) { | ||
serverData.server.close(() => { | ||
// eslint-disable-next-line no-process-exit | ||
process.exit(); | ||
}); | ||
} else { | ||
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); | ||
}); | ||
}); | ||
} | ||
if (server.options.stdin) { | ||
process.stdin.on('end', closeAndExit); | ||
process.stdin.resume(); | ||
} | ||
} | ||
module.exports = setupExitSignals; |
'use strict'; | ||
const logger = require('webpack-log'); | ||
const colors = require('./colors'); | ||
const runOpen = require('./runOpen'); | ||
// TODO: don't emit logs when webpack-dev-server is used via Node.js API | ||
function status(uri, options, log, useColor) { | ||
if (options.quiet === true) { | ||
// Add temporary logger to output just the status of the dev server | ||
log = logger({ | ||
name: 'wds', | ||
level: 'info', | ||
timestamp: options.logTime, | ||
}); | ||
} | ||
function status(uri, options, logger, useColor) { | ||
logger.info(`Project is running at ${colors.info(useColor, uri)}`); | ||
const contentBase = Array.isArray(options.contentBase) | ||
? options.contentBase.join(', ') | ||
: options.contentBase; | ||
if (options.socket) { | ||
log.info(`Listening to socket at ${colors.info(useColor, options.socket)}`); | ||
} else { | ||
log.info(`Project is running at ${colors.info(useColor, uri)}`); | ||
if (options.dev && options.dev.publicPath) { | ||
logger.info( | ||
`webpack output is served from ${colors.info( | ||
useColor, | ||
options.dev.publicPath | ||
)}` | ||
); | ||
} | ||
log.info( | ||
`webpack output is served from ${colors.info(useColor, options.publicPath)}` | ||
); | ||
if (contentBase) { | ||
log.info( | ||
if (options.static && options.static.length > 0) { | ||
logger.info( | ||
`Content not from webpack is served from ${colors.info( | ||
useColor, | ||
contentBase | ||
options.static.map((staticOption) => staticOption.directory).join(', ') | ||
)}` | ||
@@ -42,3 +28,3 @@ ); | ||
if (options.historyApiFallback) { | ||
log.info( | ||
logger.info( | ||
`404s will fallback to ${colors.info( | ||
@@ -52,3 +38,3 @@ useColor, | ||
if (options.bonjour) { | ||
log.info( | ||
logger.info( | ||
'Broadcasting "http" with subtype of "webpack" via ZeroConf DNS (Bonjour)' | ||
@@ -59,3 +45,3 @@ ); | ||
if (options.open) { | ||
runOpen(uri, options, log); | ||
runOpen(uri, options, logger); | ||
} | ||
@@ -62,0 +48,0 @@ } |
'use strict'; | ||
/* eslint-disable | ||
no-shadow, | ||
no-undefined | ||
*/ | ||
const webpack = require('webpack'); | ||
const addEntries = require('./addEntries'); | ||
const getSocketClientPath = require('./getSocketClientPath'); | ||
const DevServerPlugin = require('./DevServerPlugin'); | ||
function updateCompiler(compiler, options) { | ||
if (options.inline !== false) { | ||
const findHMRPlugin = (config) => { | ||
if (!config.plugins) { | ||
return undefined; | ||
} | ||
return config.plugins.find( | ||
(plugin) => plugin.constructor === webpack.HotModuleReplacementPlugin | ||
); | ||
}; | ||
const compilers = []; | ||
const compilersWithoutHMR = []; | ||
let webpackConfig; | ||
if (compiler.compilers) { | ||
webpackConfig = []; | ||
compiler.compilers.forEach((compiler) => { | ||
webpackConfig.push(compiler.options); | ||
compilers.push(compiler); | ||
if (!findHMRPlugin(compiler.options)) { | ||
compilersWithoutHMR.push(compiler); | ||
} | ||
}); | ||
} else { | ||
webpackConfig = compiler.options; | ||
compilers.push(compiler); | ||
if (!findHMRPlugin(compiler.options)) { | ||
compilersWithoutHMR.push(compiler); | ||
} | ||
} | ||
// it's possible that we should clone the config before doing | ||
// this, but it seems safe not to since it actually reflects | ||
// the changes we are making to the compiler | ||
// important: this relies on the fact that addEntries now | ||
// prevents duplicate new entries. | ||
addEntries(webpackConfig, options); | ||
compilers.forEach((compiler) => { | ||
const config = compiler.options; | ||
compiler.hooks.entryOption.call(config.context, config.entry); | ||
const providePlugin = new webpack.ProvidePlugin({ | ||
__webpack_dev_server_client__: getSocketClientPath(options), | ||
}); | ||
providePlugin.apply(compiler); | ||
}); | ||
// do not apply the plugin unless it didn't exist before. | ||
if (options.hot || options.hotOnly) { | ||
compilersWithoutHMR.forEach((compiler) => { | ||
// addDevServerEntrypoints above should have added the plugin | ||
// to the compiler options | ||
const plugin = findHMRPlugin(compiler.options); | ||
if (plugin) { | ||
plugin.apply(compiler); | ||
} | ||
}); | ||
} | ||
} | ||
const compilers = compiler.compilers || [compiler]; | ||
// eslint-disable-next-line no-shadow | ||
compilers.forEach((compiler) => { | ||
new DevServerPlugin(options).apply(compiler); | ||
}); | ||
} | ||
module.exports = updateCompiler; |
126
package.json
{ | ||
"name": "webpack-dev-server", | ||
"version": "3.11.0", | ||
"version": "4.0.0-beta.0", | ||
"description": "Serves a webpack app. Updates the browser on changes.", | ||
@@ -14,3 +14,3 @@ "bin": "bin/webpack-dev-server.js", | ||
"engines": { | ||
"node": ">= 6.11.5" | ||
"node": ">= 10.13.0" | ||
}, | ||
@@ -23,3 +23,2 @@ "scripts": { | ||
"commitlint": "commitlint --from=master", | ||
"security": "npm audit", | ||
"test:only": "jest --forceExit", | ||
@@ -30,8 +29,8 @@ "test:coverage": "npm run test:only -- --coverage", | ||
"pretest": "npm run lint", | ||
"prepare": "rimraf ./ssl/*.pem && npm run build:client", | ||
"build:client:default": "babel client-src/default --out-dir client --ignore \"./client-src/default/*.config.js\"", | ||
"prepare": "npm run build:client", | ||
"build:client:default": "babel client-src/default --out-dir client/default --ignore \"./client-src/default/*.config.js\"", | ||
"build:client:clients": "babel client-src/clients --out-dir client/clients", | ||
"build:client:index": "webpack ./client-src/default/index.js -o client/index.bundle.js --color --config client-src/default/webpack.config.js", | ||
"build:client:live": "webpack ./client-src/live/index.js -o client/live.bundle.js --color --config client-src/live/webpack.config.js", | ||
"build:client:sockjs": "webpack ./client-src/sockjs/index.js -o client/sockjs.bundle.js --color --config client-src/sockjs/webpack.config.js", | ||
"build:client:index": "webpack --color --config client-src/default/webpack.config.js", | ||
"build:client:sockjs": "webpack --color --config client-src/sockjs/webpack.config.js", | ||
"build:client:transpiled-modules": "webpack --color --config client-src/transpiled-modules/webpack.config.js", | ||
"build:client": "rimraf ./client/* && npm-run-all -s -l -p \"build:client:**\"", | ||
@@ -44,76 +43,73 @@ "webpack-dev-server": "node examples/run-example.js", | ||
"bonjour": "^3.5.0", | ||
"chokidar": "^2.1.8", | ||
"chokidar": "^3.4.3", | ||
"compression": "^1.7.4", | ||
"connect-history-api-fallback": "^1.6.0", | ||
"debug": "^4.1.1", | ||
"del": "^4.1.1", | ||
"del": "^6.0.0", | ||
"express": "^4.17.1", | ||
"find-cache-dir": "^3.3.1", | ||
"graceful-fs": "^4.2.4", | ||
"html-entities": "^1.3.1", | ||
"http-proxy-middleware": "0.19.1", | ||
"import-local": "^2.0.0", | ||
"internal-ip": "^4.3.0", | ||
"http-proxy-middleware": "^1.0.6", | ||
"internal-ip": "^6.2.0", | ||
"ip": "^1.1.5", | ||
"is-absolute-url": "^3.0.3", | ||
"killable": "^1.0.1", | ||
"loglevel": "^1.6.8", | ||
"opn": "^5.5.0", | ||
"p-retry": "^3.0.1", | ||
"portfinder": "^1.0.26", | ||
"schema-utils": "^1.0.0", | ||
"selfsigned": "^1.10.7", | ||
"semver": "^6.3.0", | ||
"open": "^7.3.0", | ||
"p-retry": "^4.2.0", | ||
"portfinder": "^1.0.28", | ||
"schema-utils": "^3.0.0", | ||
"selfsigned": "^1.10.8", | ||
"serve-index": "^1.9.1", | ||
"sockjs": "0.3.20", | ||
"sockjs-client": "1.4.0", | ||
"sockjs": "0.3.21", | ||
"sockjs-client": "1.5.0", | ||
"spdy": "^4.0.2", | ||
"strip-ansi": "^3.0.1", | ||
"supports-color": "^6.1.0", | ||
"strip-ansi": "^6.0.0", | ||
"url": "^0.11.0", | ||
"webpack-dev-middleware": "^3.7.2", | ||
"webpack-log": "^2.0.0", | ||
"ws": "^6.2.1", | ||
"yargs": "^13.3.2" | ||
"util": "^0.12.3", | ||
"webpack-dev-middleware": "^4.0.2", | ||
"ws": "^7.4.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "^7.8.4", | ||
"@babel/core": "^7.9.6", | ||
"@babel/plugin-transform-runtime": "^7.9.6", | ||
"@babel/preset-env": "^7.9.6", | ||
"@babel/runtime": "^7.9.6", | ||
"@commitlint/cli": "^8.3.5", | ||
"@commitlint/config-conventional": "^8.3.4", | ||
"babel-loader": "^8.1.0", | ||
"@babel/cli": "^7.12.8", | ||
"@babel/core": "^7.12.9", | ||
"@babel/plugin-transform-runtime": "^7.12.1", | ||
"@babel/preset-env": "^7.12.7", | ||
"@babel/runtime": "^7.12.5", | ||
"@commitlint/cli": "^11.0.0", | ||
"@commitlint/config-conventional": "^11.0.0", | ||
"@jest/test-sequencer": "^26.6.3", | ||
"acorn": "^8.0.4", | ||
"babel-jest": "^26.6.3", | ||
"babel-loader": "^8.2.2", | ||
"body-parser": "^1.19.0", | ||
"commitlint-azure-pipelines-cli": "^1.0.3", | ||
"copy-webpack-plugin": "^5.1.1", | ||
"css-loader": "^2.1.1", | ||
"eslint": "^6.8.0", | ||
"eslint-config-prettier": "^6.11.0", | ||
"css-loader": "^5.0.1", | ||
"eslint": "^7.14.0", | ||
"eslint-config-prettier": "^6.15.0", | ||
"eslint-config-webpack": "^1.2.5", | ||
"eslint-plugin-import": "^2.20.2", | ||
"execa": "^1.0.0", | ||
"file-loader": "^5.1.0", | ||
"html-loader": "^0.5.5", | ||
"html-webpack-plugin": "^3.2.0", | ||
"husky": "^4.2.5", | ||
"jest": "^24.9.0", | ||
"jest-junit": "^10.0.0", | ||
"jquery": "^3.5.1", | ||
"less": "^3.11.1", | ||
"less-loader": "^5.0.0", | ||
"lint-staged": "^10.2.2", | ||
"marked": "^0.8.2", | ||
"memfs": "^3.1.2", | ||
"eslint-plugin-import": "^2.22.1", | ||
"execa": "^4.1.0", | ||
"file-loader": "^6.2.0", | ||
"html-webpack-plugin": "^4.5.0", | ||
"husky": "^4.3.0", | ||
"jest": "^26.6.3", | ||
"jest-circus": "^26.6.3", | ||
"less": "^3.12.2", | ||
"less-loader": "^7.1.0", | ||
"lint-staged": "^10.5.2", | ||
"marked": "^1.2.5", | ||
"memfs": "^3.2.0", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^1.19.1", | ||
"puppeteer": "^1.20.0", | ||
"prettier": "^2.2.0", | ||
"puppeteer": "^5.5.0", | ||
"require-from-string": "^2.0.2", | ||
"rimraf": "^3.0.2", | ||
"standard-version": "^8.0.0", | ||
"style-loader": "^1.2.1", | ||
"supertest": "^4.0.2", | ||
"standard-version": "^9.0.0", | ||
"style-loader": "^2.0.0", | ||
"supertest": "^6.0.1", | ||
"tcp-port-used": "^1.0.1", | ||
"typescript": "^3.8.3", | ||
"url-loader": "^3.0.0", | ||
"webpack": "^4.43.0", | ||
"webpack-cli": "^3.3.11" | ||
"typescript": "^4.1.2", | ||
"url-loader": "^4.1.1", | ||
"webpack": "^5.8.0", | ||
"webpack-cli": "^4.2.0", | ||
"webpack-merge": "^5.4.0" | ||
}, | ||
@@ -120,0 +116,0 @@ "peerDependencies": { |
@@ -9,3 +9,2 @@ <div align="center"> | ||
[![node][node]][node-url] | ||
[![deps][deps]][deps-url] | ||
[![tests][tests]][tests-url] | ||
@@ -56,10 +55,10 @@ [![coverage][cover]][cover-url] | ||
The easiest way to use it is with the CLI. In the directory where your | ||
The easiest way to use it is with the [webpack CLI](https://webpack.js.org/api/cli/). In the directory where your | ||
`webpack.config.js` is, run: | ||
```console | ||
node_modules/.bin/webpack-dev-server | ||
node_modules/.bin/webpack serve | ||
``` | ||
_**Note**: Many CLI options are available with `webpack-dev-server`. Explore this [link](https://webpack.js.org/configuration/dev-server/)._ | ||
_**Note**: Many CLI options are available with `webpack serve`. Explore this [link](https://webpack.js.org/configuration/dev-server/)._ | ||
@@ -74,3 +73,3 @@ ### With NPM Scripts | ||
"scripts": { | ||
"start:dev": "webpack-dev-server" | ||
"start:dev": "webpack serve" | ||
} | ||
@@ -150,6 +149,4 @@ ``` | ||
[node-url]: https://nodejs.org | ||
[deps]: https://david-dm.org/webpack/webpack-dev-server.svg | ||
[deps-url]: https://david-dm.org/webpack/webpack-dev-server | ||
[tests]: https://dev.azure.com/webpack/webpack-dev-server/_apis/build/status/webpack.webpack-dev-server?branchName=master | ||
[tests-url]: https://dev.azure.com/webpack/webpack-dev-server/_build/latest?definitionId=7&branchName=master | ||
[tests]: https://github.com/webpack/webpack-dev-server/workflows/webpack-dev-server/badge.svg | ||
[tests-url]: https://github.com/webpack/webpack-dev-server/actions?query=workflow%3Awebpack-dev-server | ||
[cover]: https://codecov.io/gh/webpack/webpack-dev-server/branch/master/graph/badge.svg | ||
@@ -156,0 +153,0 @@ [cover-url]: https://codecov.io/gh/webpack/webpack-dev-server |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
30
52
375388
42
2941
1
161
12
+ Addedfind-cache-dir@^3.3.1
+ Addedgraceful-fs@^4.2.4
+ Addedopen@^7.3.0
+ Addedutil@^0.12.3
+ Added@nodelib/fs.scandir@2.1.5(transitive)
+ Added@nodelib/fs.stat@2.0.5(transitive)
+ Added@nodelib/fs.walk@1.2.8(transitive)
+ Added@types/http-proxy@1.17.14(transitive)
+ Added@types/node@20.12.12(transitive)
+ Added@types/retry@0.12.0(transitive)
+ Addedaggregate-error@3.1.0(transitive)
+ Addedansi-regex@5.0.1(transitive)
+ Addedanymatch@3.1.3(transitive)
+ Addedarray-union@2.1.0(transitive)
+ Addedavailable-typed-arrays@1.0.7(transitive)
+ Addedbinary-extensions@2.3.0(transitive)
+ Addedbraces@3.0.2(transitive)
+ Addedcaniuse-lite@1.0.30001618(transitive)
+ Addedchokidar@3.6.0(transitive)
+ Addedclean-stack@2.2.0(transitive)
+ Addedcolorette@1.4.0(transitive)
+ Addedcommondir@1.0.1(transitive)
+ Addedcross-spawn@7.0.3(transitive)
+ Addeddefault-gateway@6.0.3(transitive)
+ Addeddel@6.1.1(transitive)
+ Addeddir-glob@3.0.1(transitive)
+ Addedelectron-to-chromium@1.4.769(transitive)
+ Addedexeca@5.1.1(transitive)
+ Addedfast-glob@3.3.2(transitive)
+ Addedfastq@1.17.1(transitive)
+ Addedfill-range@7.0.1(transitive)
+ Addedfind-cache-dir@3.3.2(transitive)
+ Addedfind-up@4.1.0(transitive)
+ Addedfor-each@0.3.3(transitive)
+ Addedfs-monkey@1.0.6(transitive)
+ Addedfsevents@2.3.3(transitive)
+ Addedget-stream@6.0.1(transitive)
+ Addedglob-parent@5.1.2(transitive)
+ Addedglobby@11.1.0(transitive)
+ Addedhttp-parser-js@0.5.8(transitive)
+ Addedhttp-proxy-middleware@1.3.1(transitive)
+ Addedhuman-signals@2.1.0(transitive)
+ Addedignore@5.3.1(transitive)
+ Addedindent-string@4.0.0(transitive)
+ Addedinternal-ip@6.2.0(transitive)
+ Addedip-regex@4.3.0(transitive)
+ Addedis-binary-path@2.1.0(transitive)
+ Addedis-callable@1.2.7(transitive)
+ Addedis-docker@2.2.1(transitive)
+ Addedis-generator-function@1.0.10(transitive)
+ Addedis-ip@3.1.0(transitive)
+ Addedis-number@7.0.0(transitive)
+ Addedis-path-inside@3.0.3(transitive)
+ Addedis-plain-obj@3.0.0(transitive)
+ Addedis-stream@2.0.1(transitive)
+ Addedis-typed-array@1.1.13(transitive)
+ Addedis-wsl@2.2.0(transitive)
+ Addedlocate-path@5.0.0(transitive)
+ Addedmake-dir@3.1.0(transitive)
+ Addedmap-age-cleaner@0.1.3(transitive)
+ Addedmem@8.1.1(transitive)
+ Addedmemfs@3.6.0(transitive)
+ Addedmerge2@1.4.1(transitive)
+ Addedmicromatch@4.0.5(transitive)
+ Addedmimic-fn@2.1.03.1.0(transitive)
+ Addednpm-run-path@4.0.1(transitive)
+ Addedonetime@5.1.2(transitive)
+ Addedopen@7.4.2(transitive)
+ Addedp-defer@1.0.0(transitive)
+ Addedp-event@4.2.0(transitive)
+ Addedp-locate@4.1.0(transitive)
+ Addedp-map@4.0.0(transitive)
+ Addedp-retry@4.6.2(transitive)
+ Addedp-timeout@3.2.0(transitive)
+ Addedpath-exists@4.0.0(transitive)
+ Addedpath-key@3.1.1(transitive)
+ Addedpath-type@4.0.0(transitive)
+ Addedpicocolors@1.0.1(transitive)
+ Addedpicomatch@2.3.1(transitive)
+ Addedpkg-dir@4.2.0(transitive)
+ Addedpossible-typed-array-names@1.0.0(transitive)
+ Addedqueue-microtask@1.2.3(transitive)
+ Addedreaddirp@3.6.0(transitive)
+ Addedretry@0.13.1(transitive)
+ Addedreusify@1.0.4(transitive)
+ Addedrimraf@3.0.2(transitive)
+ Addedrun-parallel@1.2.0(transitive)
+ Addedshebang-command@2.0.0(transitive)
+ Addedshebang-regex@3.0.0(transitive)
+ Addedslash@3.0.0(transitive)
+ Addedsockjs@0.3.21(transitive)
+ Addedsockjs-client@1.5.0(transitive)
+ Addedstrip-ansi@6.0.1(transitive)
+ Addedstrip-final-newline@2.0.0(transitive)
+ Addedto-regex-range@5.0.1(transitive)
+ Addedupdate-browserslist-db@1.0.16(transitive)
+ Addedutil@0.12.5(transitive)
+ Addedwebpack-dev-middleware@4.3.0(transitive)
+ Addedwebsocket-driver@0.7.4(transitive)
+ Addedwhich@2.0.2(transitive)
+ Addedwhich-typed-array@1.1.15(transitive)
+ Addedws@7.5.9(transitive)
- Removeddebug@^4.1.1
- Removedimport-local@^2.0.0
- Removedloglevel@^1.6.8
- Removedopn@^5.5.0
- Removedsemver@^6.3.0
- Removedsupports-color@^6.1.0
- Removedwebpack-log@^2.0.0
- Removedyargs@^13.3.2
- Removed@types/glob@7.2.0(transitive)
- Removed@types/minimatch@5.1.2(transitive)
- Removed@types/node@20.12.11(transitive)
- Removedajv-errors@1.0.1(transitive)
- Removedansi-colors@3.2.4(transitive)
- Removedansi-regex@2.1.14.1.1(transitive)
- Removedansi-styles@3.2.1(transitive)
- Removedanymatch@2.0.0(transitive)
- Removedarr-diff@4.0.0(transitive)
- Removedarr-flatten@1.1.0(transitive)
- Removedarr-union@3.1.0(transitive)
- Removedarray-union@1.0.2(transitive)
- Removedarray-uniq@1.0.3(transitive)
- Removedarray-unique@0.3.2(transitive)
- Removedassign-symbols@1.0.0(transitive)
- Removedasync-each@1.0.6(transitive)
- Removedasync-limiter@1.0.1(transitive)
- Removedatob@2.1.2(transitive)
- Removedbase@0.11.2(transitive)
- Removedbinary-extensions@1.13.1(transitive)
- Removedbindings@1.5.0(transitive)
- Removedbraces@2.3.2(transitive)
- Removedcache-base@1.0.1(transitive)
- Removedcamelcase@5.3.1(transitive)
- Removedcaniuse-lite@1.0.30001616(transitive)
- Removedchokidar@2.1.8(transitive)
- Removedclass-utils@0.3.6(transitive)
- Removedcliui@5.0.0(transitive)
- Removedcollection-visit@1.0.0(transitive)
- Removedcolor-convert@1.9.3(transitive)
- Removedcolor-name@1.1.3(transitive)
- Removedcomponent-emitter@1.3.1(transitive)
- Removedcopy-descriptor@0.1.1(transitive)
- Removedcross-spawn@6.0.5(transitive)
- Removeddecamelize@1.2.0(transitive)
- Removeddecode-uri-component@0.2.2(transitive)
- Removeddefault-gateway@4.2.0(transitive)
- Removeddefine-property@0.2.51.0.02.0.2(transitive)
- Removeddel@4.1.1(transitive)
- Removedelectron-to-chromium@1.4.761(transitive)
- Removedemoji-regex@7.0.3(transitive)
- Removedend-of-stream@1.4.4(transitive)
- Removederrno@0.1.8(transitive)
- Removedexeca@1.0.0(transitive)
- Removedexpand-brackets@2.1.4(transitive)
- Removedextend-shallow@2.0.13.0.2(transitive)
- Removedextglob@2.0.4(transitive)
- Removedfaye-websocket@0.10.0(transitive)
- Removedfile-uri-to-path@1.0.0(transitive)
- Removedfill-range@4.0.0(transitive)
- Removedfind-up@3.0.0(transitive)
- Removedfor-in@1.0.2(transitive)
- Removedfragment-cache@0.2.1(transitive)
- Removedfsevents@1.2.13(transitive)
- Removedget-caller-file@2.0.5(transitive)
- Removedget-stream@4.1.0(transitive)
- Removedget-value@2.0.6(transitive)
- Removedglob-parent@3.1.0(transitive)
- Removedglobby@6.1.0(transitive)
- Removedhas-flag@3.0.0(transitive)
- Removedhas-value@0.3.11.0.0(transitive)
- Removedhas-values@0.1.41.0.0(transitive)
- Removedhttp-proxy-middleware@0.19.1(transitive)
- Removedimport-local@2.0.0(transitive)
- Removedinternal-ip@4.3.0(transitive)
- Removedip-regex@2.1.0(transitive)
- Removedis-accessor-descriptor@1.0.1(transitive)
- Removedis-binary-path@1.0.1(transitive)
- Removedis-buffer@1.1.6(transitive)
- Removedis-data-descriptor@1.0.1(transitive)
- Removedis-descriptor@0.1.71.0.3(transitive)
- Removedis-extendable@0.1.11.0.1(transitive)
- Removedis-fullwidth-code-point@2.0.0(transitive)
- Removedis-glob@3.1.0(transitive)
- Removedis-number@3.0.0(transitive)
- Removedis-path-in-cwd@2.1.0(transitive)
- Removedis-path-inside@2.1.0(transitive)
- Removedis-plain-object@2.0.4(transitive)
- Removedis-stream@1.1.0(transitive)
- Removedis-windows@1.0.2(transitive)
- Removedis-wsl@1.1.0(transitive)
- Removedisobject@2.1.03.0.1(transitive)
- Removedkind-of@3.2.24.0.06.0.3(transitive)
- Removedlocate-path@3.0.0(transitive)
- Removedloglevel@1.9.1(transitive)
- Removedmap-cache@0.2.2(transitive)
- Removedmap-visit@1.0.0(transitive)
- Removedmemory-fs@0.4.1(transitive)
- Removedmicromatch@3.1.10(transitive)
- Removedmime@2.6.0(transitive)
- Removedmixin-deep@1.3.2(transitive)
- Removednan@2.19.0(transitive)
- Removednanomatch@1.2.13(transitive)
- Removednice-try@1.0.5(transitive)
- Removednormalize-path@2.1.1(transitive)
- Removednpm-run-path@2.0.2(transitive)
- Removedobject-assign@4.1.1(transitive)
- Removedobject-copy@0.1.0(transitive)
- Removedobject-visit@1.0.1(transitive)
- Removedobject.pick@1.3.0(transitive)
- Removedopn@5.5.0(transitive)
- Removedp-locate@3.0.0(transitive)
- Removedp-map@2.1.0(transitive)
- Removedp-retry@3.0.1(transitive)
- Removedpascalcase@0.1.1(transitive)
- Removedpath-dirname@1.0.2(transitive)
- Removedpath-exists@3.0.0(transitive)
- Removedpath-is-inside@1.0.2(transitive)
- Removedpath-key@2.0.1(transitive)
- Removedpicocolors@1.0.0(transitive)
- Removedpify@2.3.04.0.1(transitive)
- Removedpinkie@2.0.4(transitive)
- Removedpinkie-promise@2.0.1(transitive)
- Removedpkg-dir@3.0.0(transitive)
- Removedposix-character-classes@0.1.1(transitive)
- Removedprr@1.0.1(transitive)
- Removedpump@3.0.0(transitive)
- Removedreaddirp@2.2.1(transitive)
- Removedregex-not@1.0.2(transitive)
- Removedremove-trailing-separator@1.1.0(transitive)
- Removedrepeat-element@1.1.4(transitive)
- Removedrepeat-string@1.6.1(transitive)
- Removedrequire-directory@2.1.1(transitive)
- Removedrequire-main-filename@2.0.0(transitive)
- Removedresolve-cwd@2.0.0(transitive)
- Removedresolve-from@3.0.0(transitive)
- Removedresolve-url@0.2.1(transitive)
- Removedret@0.1.15(transitive)
- Removedretry@0.12.0(transitive)
- Removedrimraf@2.7.1(transitive)
- Removedsafe-regex@1.1.0(transitive)
- Removedschema-utils@1.0.0(transitive)
- Removedsemver@5.7.2(transitive)
- Removedset-blocking@2.0.0(transitive)
- Removedset-value@2.0.1(transitive)
- Removedshebang-command@1.2.0(transitive)
- Removedshebang-regex@1.0.0(transitive)
- Removedsnapdragon@0.8.2(transitive)
- Removedsnapdragon-node@2.1.1(transitive)
- Removedsnapdragon-util@3.0.1(transitive)
- Removedsockjs@0.3.20(transitive)
- Removedsockjs-client@1.4.0(transitive)
- Removedsource-map@0.5.7(transitive)
- Removedsource-map-resolve@0.5.3(transitive)
- Removedsource-map-url@0.4.1(transitive)
- Removedsplit-string@3.1.0(transitive)
- Removedstatic-extend@0.1.2(transitive)
- Removedstring-width@3.1.0(transitive)
- Removedstrip-ansi@3.0.15.2.0(transitive)
- Removedstrip-eof@1.0.0(transitive)
- Removedsupports-color@6.1.0(transitive)
- Removedto-object-path@0.3.0(transitive)
- Removedto-regex@3.0.2(transitive)
- Removedto-regex-range@2.1.1(transitive)
- Removedunion-value@1.0.1(transitive)
- Removedunset-value@1.0.0(transitive)
- Removedupath@1.2.0(transitive)
- Removedupdate-browserslist-db@1.0.15(transitive)
- Removedurix@0.1.0(transitive)
- Removeduse@3.1.1(transitive)
- Removedwebpack-dev-middleware@3.7.3(transitive)
- Removedwebpack-log@2.0.0(transitive)
- Removedwebsocket-driver@0.6.5(transitive)
- Removedwhich@1.3.1(transitive)
- Removedwhich-module@2.0.1(transitive)
- Removedwrap-ansi@5.1.0(transitive)
- Removedws@6.2.2(transitive)
- Removedy18n@4.0.3(transitive)
- Removedyargs@13.3.2(transitive)
- Removedyargs-parser@13.1.2(transitive)
Updatedchokidar@^3.4.3
Updateddel@^6.0.0
Updatedhttp-proxy-middleware@^1.0.6
Updatedinternal-ip@^6.2.0
Updatedp-retry@^4.2.0
Updatedportfinder@^1.0.28
Updatedschema-utils@^3.0.0
Updatedselfsigned@^1.10.8
Updatedsockjs@0.3.21
Updatedsockjs-client@1.5.0
Updatedstrip-ansi@^6.0.0
Updatedws@^7.4.0