webpack-dev-server 3.11.3 → 4.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +596 -0
- package/README.md +87 -12
- package/bin/cli-flags.js +338 -112
- package/bin/webpack-dev-server.js +135 -144
- package/client/clients/BaseClient.js +2 -4
- package/client/clients/SockJSClient.js +13 -13
- package/client/clients/WebsocketClient.js +10 -13
- package/client/index.js +106 -58
- package/client/modules/logger/SyncBailHookFake.js +10 -0
- package/client/modules/logger/index.js +3463 -0
- package/client/modules/sockjs-client/index.js +6633 -0
- package/client/modules/strip-ansi/index.js +87 -0
- package/client/overlay.js +5 -4
- package/client/socket.js +5 -10
- package/client/utils/createSocketURL.js +81 -0
- package/client/utils/getCurrentScriptSource.js +7 -4
- package/client/utils/log.js +9 -38
- package/client/utils/parseURL.js +43 -0
- package/client/utils/reloadApp.js +2 -3
- package/client/utils/sendMessage.js +1 -1
- package/client/webpack.config.js +57 -0
- package/lib/Server.js +425 -403
- package/lib/options.json +370 -334
- package/lib/servers/SockJSServer.js +14 -8
- package/lib/servers/WebsocketServer.js +5 -4
- package/lib/utils/DevServerPlugin.js +218 -0
- package/lib/utils/createDomain.js +13 -11
- package/lib/utils/findPort.js +3 -10
- package/lib/utils/getCertificate.js +7 -2
- package/lib/utils/getColorsOption.js +15 -0
- package/lib/utils/getCompilerConfigArray.js +8 -0
- package/lib/utils/getSocketClientPath.d.ts +3 -0
- package/lib/utils/getSocketClientPath.js +1 -0
- package/lib/utils/getSocketServerImplementation.js +1 -1
- package/lib/utils/getStatsOption.js +16 -0
- package/lib/utils/normalizeOptions.js +96 -15
- package/lib/utils/routes.js +34 -62
- package/lib/utils/runBonjour.js +4 -3
- package/lib/utils/runOpen.js +67 -21
- package/lib/utils/setupExitSignals.js +15 -11
- package/package.json +65 -70
- package/bin/options.js +0 -187
- package/client/index.bundle.js +0 -1
- package/client/live.bundle.js +0 -25
- package/client/live.html +0 -1
- package/client/sockjs.bundle.js +0 -1
- package/client/utils/createSocketUrl.js +0 -88
- package/lib/utils/addEntries.js +0 -160
- package/lib/utils/createConfig.js +0 -233
- package/lib/utils/createLogger.js +0 -23
- package/lib/utils/defaultPort.js +0 -3
- package/lib/utils/defaultTo.js +0 -7
- package/lib/utils/getVersions.js +0 -10
- package/lib/utils/processOptions.js +0 -44
- package/lib/utils/status.js +0 -61
- package/lib/utils/tryParseInt.js +0 -13
- package/lib/utils/updateCompiler.js +0 -73
- package/ssl/.gitkeep +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/* eslint-disable
|
|
4
|
-
class-methods-use-this
|
|
5
|
-
func-names
|
|
4
|
+
class-methods-use-this
|
|
6
5
|
*/
|
|
7
6
|
const sockjs = require('sockjs');
|
|
8
7
|
const BaseServer = require('./BaseServer');
|
|
@@ -13,9 +12,13 @@ const BaseServer = require('./BaseServer');
|
|
|
13
12
|
{
|
|
14
13
|
const SockjsSession = require('sockjs/lib/transport').Session;
|
|
15
14
|
const decorateConnection = SockjsSession.prototype.decorateConnection;
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line func-names
|
|
17
|
+
SockjsSession.prototype.decorateConnection = function (req) {
|
|
17
18
|
decorateConnection.call(this, req);
|
|
19
|
+
|
|
18
20
|
const connection = this.connection;
|
|
21
|
+
|
|
19
22
|
if (
|
|
20
23
|
connection.headers &&
|
|
21
24
|
!('origin' in connection.headers) &&
|
|
@@ -30,21 +33,24 @@ module.exports = class SockJSServer extends BaseServer {
|
|
|
30
33
|
// options has: error (function), debug (function), server (http/s server), path (string)
|
|
31
34
|
constructor(server) {
|
|
32
35
|
super(server);
|
|
36
|
+
|
|
33
37
|
this.socket = sockjs.createServer({
|
|
34
38
|
// Use provided up-to-date sockjs-client
|
|
35
39
|
sockjs_url: '/__webpack_dev_server__/sockjs.bundle.js',
|
|
36
|
-
// Limit useless logs
|
|
40
|
+
// Default logger is very annoy. Limit useless logs.
|
|
37
41
|
log: (severity, line) => {
|
|
38
42
|
if (severity === 'error') {
|
|
39
|
-
this.server.
|
|
43
|
+
this.server.logger.error(line);
|
|
44
|
+
} else if (severity === 'info') {
|
|
45
|
+
this.server.logger.log(line);
|
|
40
46
|
} else {
|
|
41
|
-
this.server.
|
|
47
|
+
this.server.logger.debug(line);
|
|
42
48
|
}
|
|
43
49
|
},
|
|
44
50
|
});
|
|
45
51
|
|
|
46
|
-
this.socket.installHandlers(this.server.
|
|
47
|
-
prefix: this.server.
|
|
52
|
+
this.socket.installHandlers(this.server.server, {
|
|
53
|
+
prefix: this.server.options.client.path,
|
|
48
54
|
});
|
|
49
55
|
}
|
|
50
56
|
|
|
@@ -9,12 +9,13 @@ const BaseServer = require('./BaseServer');
|
|
|
9
9
|
module.exports = class WebsocketServer extends BaseServer {
|
|
10
10
|
constructor(server) {
|
|
11
11
|
super(server);
|
|
12
|
+
|
|
12
13
|
this.wsServer = new ws.Server({
|
|
13
14
|
noServer: true,
|
|
14
|
-
path: this.server.
|
|
15
|
+
path: this.server.options.client.path,
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
this.server.
|
|
18
|
+
this.server.server.on('upgrade', (req, sock, head) => {
|
|
18
19
|
if (!this.wsServer.shouldHandle(req)) {
|
|
19
20
|
return;
|
|
20
21
|
}
|
|
@@ -25,7 +26,7 @@ module.exports = class WebsocketServer extends BaseServer {
|
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
this.wsServer.on('error', (err) => {
|
|
28
|
-
this.server.
|
|
29
|
+
this.server.logger.error(err.message);
|
|
29
30
|
});
|
|
30
31
|
|
|
31
32
|
const noop = () => {};
|
|
@@ -39,7 +40,7 @@ module.exports = class WebsocketServer extends BaseServer {
|
|
|
39
40
|
socket.isAlive = false;
|
|
40
41
|
socket.ping(noop);
|
|
41
42
|
});
|
|
42
|
-
}, this.server.
|
|
43
|
+
}, this.server.wsHeartbeatInterval);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
send(connection, message) {
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const webpack = require('webpack');
|
|
4
|
+
const createDomain = require('./createDomain');
|
|
5
|
+
const getSocketClientPath = require('./getSocketClientPath');
|
|
6
|
+
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
const EntryPlugin = webpack.EntryPlugin;
|
|
9
|
+
|
|
10
|
+
class DevServerPlugin {
|
|
11
|
+
/**
|
|
12
|
+
* @param {?Object} options - Dev-Server options
|
|
13
|
+
*/
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.options = options;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* An Entry, it can be of type string or string[] or Object<string | string[],string>
|
|
20
|
+
* @typedef {(string[] | string | Object<string | string[],string>)} Entry
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Apply the plugin
|
|
25
|
+
* @param {Object} compiler the compiler instance
|
|
26
|
+
* @returns {void}
|
|
27
|
+
*/
|
|
28
|
+
apply(compiler) {
|
|
29
|
+
const { options } = this;
|
|
30
|
+
|
|
31
|
+
/** @type {string} */
|
|
32
|
+
const domain = createDomain(options);
|
|
33
|
+
/** @type {string} */
|
|
34
|
+
const host =
|
|
35
|
+
options.client && options.client.host
|
|
36
|
+
? `&host=${options.client.host}`
|
|
37
|
+
: '';
|
|
38
|
+
/** @type {string} */
|
|
39
|
+
let path = '';
|
|
40
|
+
|
|
41
|
+
// only add the path if it is not default
|
|
42
|
+
if (
|
|
43
|
+
options.client &&
|
|
44
|
+
options.client.path &&
|
|
45
|
+
options.client.path !== '/ws'
|
|
46
|
+
) {
|
|
47
|
+
path = `&path=${options.client.path}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** @type {string} */
|
|
51
|
+
const port =
|
|
52
|
+
(options.client && options.client.port) || options.port
|
|
53
|
+
? `&port=${options.client.port || options.port}`
|
|
54
|
+
: '';
|
|
55
|
+
|
|
56
|
+
/** @type {string} */
|
|
57
|
+
const logging =
|
|
58
|
+
options.client && options.client.logging
|
|
59
|
+
? `&logging=${options.client.logging}`
|
|
60
|
+
: '';
|
|
61
|
+
|
|
62
|
+
/** @type {string} */
|
|
63
|
+
const clientEntry = `${require.resolve(
|
|
64
|
+
'../../client/'
|
|
65
|
+
)}?${domain}${host}${path}${port}${logging}`;
|
|
66
|
+
|
|
67
|
+
/** @type {(string[] | string)} */
|
|
68
|
+
let hotEntry;
|
|
69
|
+
|
|
70
|
+
if (options.hot === 'only') {
|
|
71
|
+
hotEntry = require.resolve('webpack/hot/only-dev-server');
|
|
72
|
+
} else if (options.hot) {
|
|
73
|
+
hotEntry = require.resolve('webpack/hot/dev-server');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* prependEntry Method for webpack 4
|
|
77
|
+
* @param {Entry} originalEntry
|
|
78
|
+
* @param {Entry} additionalEntries
|
|
79
|
+
* @returns {Entry}
|
|
80
|
+
*/
|
|
81
|
+
const prependEntry = (originalEntry, additionalEntries) => {
|
|
82
|
+
if (typeof originalEntry === 'function') {
|
|
83
|
+
return () =>
|
|
84
|
+
Promise.resolve(originalEntry()).then((entry) =>
|
|
85
|
+
prependEntry(entry, additionalEntries)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (typeof originalEntry === 'object' && !Array.isArray(originalEntry)) {
|
|
90
|
+
/** @type {Object<string,string>} */
|
|
91
|
+
const clone = {};
|
|
92
|
+
|
|
93
|
+
Object.keys(originalEntry).forEach((key) => {
|
|
94
|
+
// entry[key] should be a string here
|
|
95
|
+
const entryDescription = originalEntry[key];
|
|
96
|
+
clone[key] = prependEntry(entryDescription, additionalEntries);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return clone;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// in this case, entry is a string or an array.
|
|
103
|
+
// make sure that we do not add duplicates.
|
|
104
|
+
/** @type {Entry} */
|
|
105
|
+
const entriesClone = additionalEntries.slice(0);
|
|
106
|
+
[].concat(originalEntry).forEach((newEntry) => {
|
|
107
|
+
if (!entriesClone.includes(newEntry)) {
|
|
108
|
+
entriesClone.push(newEntry);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
return entriesClone;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
*
|
|
116
|
+
* Description of the option for checkInject method
|
|
117
|
+
* @typedef {Function} checkInjectOptionsParam
|
|
118
|
+
* @param {Object} _config - compilerConfig
|
|
119
|
+
* @return {Boolean}
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
*
|
|
124
|
+
* @param {Boolean | checkInjectOptionsParam} option - inject(Hot|Client) it is Boolean | fn => Boolean
|
|
125
|
+
* @param {Object} _config
|
|
126
|
+
* @param {Boolean} defaultValue
|
|
127
|
+
* @return {Boolean}
|
|
128
|
+
*/
|
|
129
|
+
// eslint-disable-next-line no-shadow
|
|
130
|
+
const checkInject = (option, _config, defaultValue) => {
|
|
131
|
+
if (typeof option === 'boolean') {
|
|
132
|
+
return option;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (typeof option === 'function') {
|
|
136
|
+
return option(_config);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return defaultValue;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const compilerOptions = compiler.options;
|
|
143
|
+
|
|
144
|
+
compilerOptions.plugins = compilerOptions.plugins || [];
|
|
145
|
+
|
|
146
|
+
/** @type {boolean} */
|
|
147
|
+
const isWebTarget = compilerOptions.externalsPresets
|
|
148
|
+
? compilerOptions.externalsPresets.web
|
|
149
|
+
: [
|
|
150
|
+
'web',
|
|
151
|
+
'webworker',
|
|
152
|
+
'electron-renderer',
|
|
153
|
+
'node-webkit',
|
|
154
|
+
// eslint-disable-next-line no-undefined
|
|
155
|
+
undefined,
|
|
156
|
+
null,
|
|
157
|
+
].includes(compilerOptions.target);
|
|
158
|
+
|
|
159
|
+
/** @type {Entry} */
|
|
160
|
+
const additionalEntries = checkInject(
|
|
161
|
+
options.client ? options.client.needClientEntry : null,
|
|
162
|
+
compilerOptions,
|
|
163
|
+
isWebTarget
|
|
164
|
+
)
|
|
165
|
+
? [clientEntry]
|
|
166
|
+
: [];
|
|
167
|
+
|
|
168
|
+
if (
|
|
169
|
+
hotEntry &&
|
|
170
|
+
checkInject(
|
|
171
|
+
options.client ? options.client.needHotEntry : null,
|
|
172
|
+
compilerOptions,
|
|
173
|
+
true
|
|
174
|
+
)
|
|
175
|
+
) {
|
|
176
|
+
additionalEntries.push(hotEntry);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// use a hook to add entries if available
|
|
180
|
+
if (EntryPlugin) {
|
|
181
|
+
for (const additionalEntry of additionalEntries) {
|
|
182
|
+
new EntryPlugin(compiler.context, additionalEntry, {
|
|
183
|
+
// eslint-disable-next-line no-undefined
|
|
184
|
+
name: undefined,
|
|
185
|
+
}).apply(compiler);
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
compilerOptions.entry = prependEntry(
|
|
189
|
+
compilerOptions.entry || './src',
|
|
190
|
+
additionalEntries
|
|
191
|
+
);
|
|
192
|
+
compiler.hooks.entryOption.call(
|
|
193
|
+
compilerOptions.context,
|
|
194
|
+
compilerOptions.entry
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const providePlugin = new webpack.ProvidePlugin({
|
|
199
|
+
__webpack_dev_server_client__: getSocketClientPath(options),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
providePlugin.apply(compiler);
|
|
203
|
+
|
|
204
|
+
if (
|
|
205
|
+
hotEntry &&
|
|
206
|
+
!compilerOptions.plugins.find(
|
|
207
|
+
(p) => p.constructor === webpack.HotModuleReplacementPlugin
|
|
208
|
+
)
|
|
209
|
+
) {
|
|
210
|
+
// apply the HMR plugin, if it didn't exist before.
|
|
211
|
+
const plugin = new webpack.HotModuleReplacementPlugin();
|
|
212
|
+
|
|
213
|
+
plugin.apply(compiler);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = DevServerPlugin;
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const url = require('url');
|
|
4
|
-
const ip = require('internal-ip');
|
|
5
4
|
|
|
6
5
|
function createDomain(options, server) {
|
|
7
6
|
const protocol = options.https ? 'https' : 'http';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
// use location hostname and port by default in createSocketURL
|
|
8
|
+
// ipv6 detection is not required as 0.0.0.0 is just used as a placeholder
|
|
9
|
+
let hostname;
|
|
10
|
+
|
|
11
|
+
if (server) {
|
|
12
|
+
hostname = server.address().address;
|
|
13
|
+
} else {
|
|
14
|
+
hostname = '0.0.0.0';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const port = server ? server.address().port : 0;
|
|
11
18
|
|
|
12
|
-
// eslint-disable-next-line no-nested-ternary
|
|
13
|
-
const port = options.socket ? 0 : server ? server.address().port : 0;
|
|
14
19
|
// use explicitly defined public url
|
|
15
20
|
// (prefix with protocol if not explicitly given)
|
|
16
21
|
if (options.public) {
|
|
@@ -18,12 +23,9 @@ function createDomain(options, server) {
|
|
|
18
23
|
? `${options.public}`
|
|
19
24
|
: `${protocol}://${options.public}`;
|
|
20
25
|
}
|
|
26
|
+
|
|
21
27
|
// the formatted domain (url without path) of the webpack server
|
|
22
|
-
return url.format({
|
|
23
|
-
protocol,
|
|
24
|
-
hostname,
|
|
25
|
-
port,
|
|
26
|
-
});
|
|
28
|
+
return url.format({ protocol, hostname, port });
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
module.exports = createDomain;
|
package/lib/utils/findPort.js
CHANGED
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
const pRetry = require('p-retry');
|
|
4
4
|
const portfinder = require('portfinder');
|
|
5
|
-
const defaultPort = require('./defaultPort');
|
|
6
|
-
const defaultTo = require('./defaultTo');
|
|
7
|
-
const tryParseInt = require('./tryParseInt');
|
|
8
5
|
|
|
9
6
|
function runPortFinder() {
|
|
10
7
|
return new Promise((resolve, reject) => {
|
|
11
|
-
|
|
8
|
+
// default port
|
|
9
|
+
portfinder.basePort = 8080;
|
|
12
10
|
portfinder.getPort((error, port) => {
|
|
13
11
|
if (error) {
|
|
14
12
|
return reject(error);
|
|
@@ -26,12 +24,7 @@ function findPort(port) {
|
|
|
26
24
|
|
|
27
25
|
// Try to find unused port and listen on it for 3 times,
|
|
28
26
|
// if port is not specified in options.
|
|
29
|
-
|
|
30
|
-
// so the tryParseInt function is introduced to handle NaN
|
|
31
|
-
const defaultPortRetry = defaultTo(
|
|
32
|
-
tryParseInt(process.env.DEFAULT_PORT_RETRY),
|
|
33
|
-
3
|
|
34
|
-
);
|
|
27
|
+
const defaultPortRetry = parseInt(process.env.DEFAULT_PORT_RETRY, 10) || 3;
|
|
35
28
|
|
|
36
29
|
return pRetry(runPortFinder, { retries: defaultPortRetry });
|
|
37
30
|
}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
|
-
const
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const fs = require('graceful-fs');
|
|
5
6
|
const del = require('del');
|
|
7
|
+
const findCacheDir = require('find-cache-dir');
|
|
6
8
|
const createCertificate = require('./createCertificate');
|
|
7
9
|
|
|
8
10
|
function getCertificate(logger) {
|
|
9
11
|
// Use a self-signed certificate if no certificate was configured.
|
|
10
12
|
// Cycle certs every 24 hours
|
|
11
|
-
const
|
|
13
|
+
const certificateDir =
|
|
14
|
+
findCacheDir({ name: 'webpack-dev-server' }) || os.tmpdir();
|
|
15
|
+
const certificatePath = path.join(certificateDir, 'server.pem');
|
|
12
16
|
|
|
13
17
|
let certificateExists = fs.existsSync(certificatePath);
|
|
14
18
|
|
|
@@ -34,6 +38,7 @@ function getCertificate(logger) {
|
|
|
34
38
|
const attributes = [{ name: 'commonName', value: 'localhost' }];
|
|
35
39
|
const pems = createCertificate(attributes);
|
|
36
40
|
|
|
41
|
+
fs.mkdirSync(certificateDir, { recursive: true });
|
|
37
42
|
fs.writeFileSync(certificatePath, pems.private + pems.cert, {
|
|
38
43
|
encoding: 'utf8',
|
|
39
44
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const getStatsOption = require('./getStatsOption');
|
|
4
|
+
|
|
5
|
+
function getColorsOption(configArr) {
|
|
6
|
+
const statsOption = getStatsOption(configArr);
|
|
7
|
+
let colors = false;
|
|
8
|
+
if (typeof statsOption === 'object' && statsOption.colors) {
|
|
9
|
+
colors = statsOption.colors;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return colors;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = getColorsOption;
|
|
@@ -30,7 +30,7 @@ function getSocketServerImplementation(options) {
|
|
|
30
30
|
|
|
31
31
|
if (!serverImplFound) {
|
|
32
32
|
throw new Error(
|
|
33
|
-
"transportMode.server must be a string denoting a default implementation (e.g. '
|
|
33
|
+
"transportMode.server must be a string denoting a default implementation (e.g. 'ws', 'sockjs'), a full path to " +
|
|
34
34
|
'a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer) ' +
|
|
35
35
|
'via require.resolve(...), or the class itself which extends BaseServer'
|
|
36
36
|
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function getStatsOption(configArr) {
|
|
4
|
+
const isEmptyObject = (val) =>
|
|
5
|
+
typeof val === 'object' && Object.keys(val).length === 0;
|
|
6
|
+
|
|
7
|
+
// in webpack@4 stats will not be defined if not provided,
|
|
8
|
+
// but in webpack@5 it will be an empty object
|
|
9
|
+
const statsConfig = configArr.find(
|
|
10
|
+
(conf) =>
|
|
11
|
+
typeof conf === 'object' && conf.stats && !isEmptyObject(conf.stats)
|
|
12
|
+
);
|
|
13
|
+
return statsConfig ? statsConfig.stats : {};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = getStatsOption;
|
|
@@ -1,22 +1,83 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const isAbsoluteUrl = require('is-absolute-url');
|
|
5
|
+
const getCompilerConfigArray = require('./getCompilerConfigArray');
|
|
6
6
|
|
|
7
7
|
function normalizeOptions(compiler, options) {
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
// TODO: improve this to not use .find for compiler watchOptions
|
|
9
|
+
const configArr = getCompilerConfigArray(compiler);
|
|
10
|
+
const watchOptionsConfig = configArr.find(
|
|
11
|
+
(config) => config.watch !== false && config.watchOptions
|
|
12
|
+
);
|
|
13
|
+
const watchOptions = watchOptionsConfig
|
|
14
|
+
? watchOptionsConfig.watchOptions
|
|
15
|
+
: {};
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
const defaultOptionsForStatic = {
|
|
18
|
+
directory: path.join(process.cwd(), 'public'),
|
|
19
|
+
staticOptions: {},
|
|
20
|
+
publicPath: ['/'],
|
|
21
|
+
serveIndex: { icons: true },
|
|
22
|
+
// Respect options from compiler watchOptions
|
|
23
|
+
watch: watchOptions,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (typeof options.static === 'undefined') {
|
|
27
|
+
options.static = [defaultOptionsForStatic];
|
|
28
|
+
} else if (typeof options.static === 'boolean') {
|
|
29
|
+
options.static = options.static ? [defaultOptionsForStatic] : false;
|
|
30
|
+
} else if (typeof options.static === 'string') {
|
|
31
|
+
options.static = [
|
|
32
|
+
{ ...defaultOptionsForStatic, directory: options.static },
|
|
33
|
+
];
|
|
34
|
+
} else if (Array.isArray(options.static)) {
|
|
35
|
+
options.static = options.static.map((item) => {
|
|
36
|
+
if (typeof item === 'string') {
|
|
37
|
+
return { ...defaultOptionsForStatic, directory: item };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return { ...defaultOptionsForStatic, ...item };
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
options.static = [{ ...defaultOptionsForStatic, ...options.static }];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (options.static) {
|
|
47
|
+
options.static.forEach((staticOption) => {
|
|
48
|
+
if (isAbsoluteUrl(staticOption.directory)) {
|
|
49
|
+
throw new Error('Using a URL as static.directory is not supported');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ensure that publicPath is an array
|
|
53
|
+
if (typeof staticOption.publicPath === 'string') {
|
|
54
|
+
staticOption.publicPath = [staticOption.publicPath];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ensure that watch is an object if true
|
|
58
|
+
if (staticOption.watch === true) {
|
|
59
|
+
staticOption.watch = defaultOptionsForStatic.watch;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ensure that serveIndex is an object if true
|
|
63
|
+
if (staticOption.serveIndex === true) {
|
|
64
|
+
staticOption.serveIndex = defaultOptionsForStatic.serveIndex;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
options.hot =
|
|
70
|
+
typeof options.hot === 'boolean' || options.hot === 'only'
|
|
71
|
+
? options.hot
|
|
72
|
+
: true;
|
|
73
|
+
options.liveReload =
|
|
74
|
+
typeof options.liveReload !== 'undefined' ? options.liveReload : true;
|
|
14
75
|
|
|
15
76
|
// normalize transportMode option
|
|
16
|
-
if (options.transportMode === undefined) {
|
|
77
|
+
if (typeof options.transportMode === 'undefined') {
|
|
17
78
|
options.transportMode = {
|
|
18
|
-
server: '
|
|
19
|
-
client: '
|
|
79
|
+
server: 'ws',
|
|
80
|
+
client: 'ws',
|
|
20
81
|
};
|
|
21
82
|
} else {
|
|
22
83
|
switch (typeof options.transportMode) {
|
|
@@ -28,13 +89,33 @@ function normalizeOptions(compiler, options) {
|
|
|
28
89
|
break;
|
|
29
90
|
// if not a string, it is an object
|
|
30
91
|
default:
|
|
31
|
-
options.transportMode.server = options.transportMode.server || '
|
|
32
|
-
options.transportMode.client = options.transportMode.client || '
|
|
92
|
+
options.transportMode.server = options.transportMode.server || 'ws';
|
|
93
|
+
options.transportMode.client = options.transportMode.client || 'ws';
|
|
33
94
|
}
|
|
34
95
|
}
|
|
35
96
|
|
|
36
|
-
if (!options.
|
|
37
|
-
options.
|
|
97
|
+
if (!options.client) {
|
|
98
|
+
options.client = {};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Enable client overlay by default
|
|
102
|
+
if (typeof options.client.overlay === 'undefined') {
|
|
103
|
+
options.client.overlay = true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
options.client.path = `/${
|
|
107
|
+
options.client.path ? options.client.path.replace(/^\/|\/$/g, '') : 'ws'
|
|
108
|
+
}`;
|
|
109
|
+
|
|
110
|
+
options.devMiddleware = options.devMiddleware || {};
|
|
111
|
+
|
|
112
|
+
if (typeof options.firewall === 'undefined') {
|
|
113
|
+
// firewall is enabled by default
|
|
114
|
+
options.firewall = true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (typeof options.setupExitSignals === 'undefined') {
|
|
118
|
+
options.setupExitSignals = true;
|
|
38
119
|
}
|
|
39
120
|
}
|
|
40
121
|
|