Socket
Socket
Sign inDemoInstall

webpack-dev-server

Package Overview
Dependencies
318
Maintainers
5
Versions
217
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.11.0 to 4.0.0-beta.0

client/default/index.bundle.js

126

bin/cli-flags.js

@@ -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);
});

@@ -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;
{
"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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc