webpack-dev-server 4.0.0-rc.0 → 4.1.1
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/README.md +3 -0
- package/bin/cli-flags.js +340 -316
- package/bin/process-arguments.js +42 -42
- package/bin/webpack-dev-server.js +28 -28
- package/client/clients/SockJSClient.js +7 -9
- package/client/clients/{WebsocketClient.js → WebSocketClient.js} +9 -10
- package/client/index.js +58 -69
- package/client/modules/logger/index.js +62 -64
- package/client/modules/sockjs-client/index.js +128 -42
- package/client/modules/strip-ansi/index.js +15 -20
- package/client/overlay.js +59 -66
- package/client/socket.js +8 -8
- package/client/utils/createSocketURL.js +12 -15
- package/client/utils/getCurrentScriptSource.js +5 -7
- package/client/utils/log.js +5 -10
- package/client/utils/parseURL.js +6 -9
- package/client/utils/reloadApp.js +42 -32
- package/client/utils/sendMessage.js +3 -5
- package/lib/Server.js +1405 -506
- package/lib/options.json +34 -9
- package/lib/servers/BaseServer.js +2 -2
- package/lib/servers/SockJSServer.js +17 -20
- package/lib/servers/WebsocketServer.js +14 -16
- package/package.json +14 -13
- package/client/modules/logger/SyncBailHookFake.js +0 -10
- package/client/webpack.config.js +0 -59
- package/lib/utils/DevServerPlugin.js +0 -352
- package/lib/utils/getCompilerConfigArray.js +0 -8
- package/lib/utils/normalizeOptions.js +0 -442
|
@@ -1,442 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const os = require('os');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const del = require('del');
|
|
6
|
-
const fs = require('graceful-fs');
|
|
7
|
-
const getCompilerConfigArray = require('./getCompilerConfigArray');
|
|
8
|
-
|
|
9
|
-
function normalizeOptions(compiler, options, logger, cacheDir) {
|
|
10
|
-
// TODO: improve this to not use .find for compiler watchOptions
|
|
11
|
-
const configArray = getCompilerConfigArray(compiler);
|
|
12
|
-
const watchOptionsConfig = configArray.find(
|
|
13
|
-
(config) => config.watch !== false && config.watchOptions
|
|
14
|
-
);
|
|
15
|
-
const watchOptions = watchOptionsConfig
|
|
16
|
-
? watchOptionsConfig.watchOptions
|
|
17
|
-
: {};
|
|
18
|
-
|
|
19
|
-
const defaultOptionsForStatic = {
|
|
20
|
-
directory: path.join(process.cwd(), 'public'),
|
|
21
|
-
staticOptions: {},
|
|
22
|
-
publicPath: ['/'],
|
|
23
|
-
serveIndex: { icons: true },
|
|
24
|
-
// Respect options from compiler watchOptions
|
|
25
|
-
watch: watchOptions,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
if (typeof options.allowedHosts === 'undefined') {
|
|
29
|
-
// allowedHosts allows some default hosts picked from
|
|
30
|
-
// `options.host` or `webSocketURL.hostname` and `localhost`
|
|
31
|
-
options.allowedHosts = 'auto';
|
|
32
|
-
}
|
|
33
|
-
if (
|
|
34
|
-
typeof options.allowedHosts === 'string' &&
|
|
35
|
-
options.allowedHosts !== 'auto' &&
|
|
36
|
-
options.allowedHosts !== 'all'
|
|
37
|
-
) {
|
|
38
|
-
// we store allowedHosts as array when supplied as string
|
|
39
|
-
options.allowedHosts = [options.allowedHosts];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
typeof options.client === 'undefined' ||
|
|
44
|
-
(typeof options.client === 'object' && options.client !== null)
|
|
45
|
-
) {
|
|
46
|
-
if (!options.client) {
|
|
47
|
-
options.client = {};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (typeof options.client.webSocketURL === 'undefined') {
|
|
51
|
-
options.client.webSocketURL = {};
|
|
52
|
-
} else if (typeof options.client.webSocketURL === 'string') {
|
|
53
|
-
const parsedURL = new URL(options.client.webSocketURL);
|
|
54
|
-
|
|
55
|
-
options.client.webSocketURL = {
|
|
56
|
-
protocol: parsedURL.protocol,
|
|
57
|
-
hostname: parsedURL.hostname,
|
|
58
|
-
port: parsedURL.port.length > 0 ? Number(parsedURL.port) : '',
|
|
59
|
-
pathname: parsedURL.pathname,
|
|
60
|
-
username: parsedURL.username,
|
|
61
|
-
password: parsedURL.password,
|
|
62
|
-
};
|
|
63
|
-
} else if (typeof options.client.webSocketURL.port === 'string') {
|
|
64
|
-
options.client.webSocketURL.port = Number(
|
|
65
|
-
options.client.webSocketURL.port
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Enable client overlay by default
|
|
70
|
-
if (typeof options.client.overlay === 'undefined') {
|
|
71
|
-
options.client.overlay = true;
|
|
72
|
-
} else if (typeof options.client.overlay !== 'boolean') {
|
|
73
|
-
options.client.overlay = {
|
|
74
|
-
errors: true,
|
|
75
|
-
warnings: true,
|
|
76
|
-
...options.client.overlay,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (typeof options.compress === 'undefined') {
|
|
82
|
-
options.compress = true;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
options.devMiddleware = options.devMiddleware || {};
|
|
86
|
-
|
|
87
|
-
options.hot =
|
|
88
|
-
typeof options.hot === 'boolean' || options.hot === 'only'
|
|
89
|
-
? options.hot
|
|
90
|
-
: true;
|
|
91
|
-
|
|
92
|
-
// if the user enables http2, we can safely enable https
|
|
93
|
-
if ((options.http2 && !options.https) || options.https === true) {
|
|
94
|
-
options.https = {
|
|
95
|
-
requestCert: false,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// https option
|
|
100
|
-
if (options.https) {
|
|
101
|
-
for (const property of ['cacert', 'pfx', 'key', 'cert']) {
|
|
102
|
-
const value = options.https[property];
|
|
103
|
-
const isBuffer = value instanceof Buffer;
|
|
104
|
-
|
|
105
|
-
if (value && !isBuffer) {
|
|
106
|
-
let stats = null;
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
stats = fs.lstatSync(fs.realpathSync(value)).isFile();
|
|
110
|
-
} catch (error) {
|
|
111
|
-
// ignore error
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// It is file
|
|
115
|
-
options.https[property] = stats
|
|
116
|
-
? fs.readFileSync(path.resolve(value))
|
|
117
|
-
: value;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
let fakeCert;
|
|
122
|
-
|
|
123
|
-
if (!options.https.key || !options.https.cert) {
|
|
124
|
-
const certificateDir = cacheDir || os.tmpdir();
|
|
125
|
-
const certificatePath = path.join(certificateDir, 'server.pem');
|
|
126
|
-
let certificateExists = fs.existsSync(certificatePath);
|
|
127
|
-
|
|
128
|
-
if (certificateExists) {
|
|
129
|
-
const certificateTtl = 1000 * 60 * 60 * 24;
|
|
130
|
-
const certificateStat = fs.statSync(certificatePath);
|
|
131
|
-
|
|
132
|
-
const now = new Date();
|
|
133
|
-
|
|
134
|
-
// cert is more than 30 days old, kill it with fire
|
|
135
|
-
if ((now - certificateStat.ctime) / certificateTtl > 30) {
|
|
136
|
-
logger.info('SSL Certificate is more than 30 days old. Removing.');
|
|
137
|
-
|
|
138
|
-
del.sync([certificatePath], { force: true });
|
|
139
|
-
|
|
140
|
-
certificateExists = false;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (!certificateExists) {
|
|
145
|
-
logger.info('Generating SSL Certificate');
|
|
146
|
-
|
|
147
|
-
const selfsigned = require('selfsigned');
|
|
148
|
-
const attributes = [{ name: 'commonName', value: 'localhost' }];
|
|
149
|
-
const pems = selfsigned.generate(attributes, {
|
|
150
|
-
algorithm: 'sha256',
|
|
151
|
-
days: 30,
|
|
152
|
-
keySize: 2048,
|
|
153
|
-
extensions: [
|
|
154
|
-
// {
|
|
155
|
-
// name: 'basicConstraints',
|
|
156
|
-
// cA: true,
|
|
157
|
-
// },
|
|
158
|
-
{
|
|
159
|
-
name: 'keyUsage',
|
|
160
|
-
keyCertSign: true,
|
|
161
|
-
digitalSignature: true,
|
|
162
|
-
nonRepudiation: true,
|
|
163
|
-
keyEncipherment: true,
|
|
164
|
-
dataEncipherment: true,
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
name: 'extKeyUsage',
|
|
168
|
-
serverAuth: true,
|
|
169
|
-
clientAuth: true,
|
|
170
|
-
codeSigning: true,
|
|
171
|
-
timeStamping: true,
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
name: 'subjectAltName',
|
|
175
|
-
altNames: [
|
|
176
|
-
{
|
|
177
|
-
// type 2 is DNS
|
|
178
|
-
type: 2,
|
|
179
|
-
value: 'localhost',
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
type: 2,
|
|
183
|
-
value: 'localhost.localdomain',
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
type: 2,
|
|
187
|
-
value: 'lvh.me',
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
type: 2,
|
|
191
|
-
value: '*.lvh.me',
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
type: 2,
|
|
195
|
-
value: '[::1]',
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
// type 7 is IP
|
|
199
|
-
type: 7,
|
|
200
|
-
ip: '127.0.0.1',
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
type: 7,
|
|
204
|
-
ip: 'fe80::1',
|
|
205
|
-
},
|
|
206
|
-
],
|
|
207
|
-
},
|
|
208
|
-
],
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
fs.mkdirSync(certificateDir, { recursive: true });
|
|
212
|
-
fs.writeFileSync(certificatePath, pems.private + pems.cert, {
|
|
213
|
-
encoding: 'utf8',
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
fakeCert = fs.readFileSync(certificatePath);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
options.https.key = options.https.key || fakeCert;
|
|
221
|
-
options.https.cert = options.https.cert || fakeCert;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (typeof options.ipc === 'boolean') {
|
|
225
|
-
const isWindows = process.platform === 'win32';
|
|
226
|
-
const pipePrefix = isWindows ? '\\\\.\\pipe\\' : os.tmpdir();
|
|
227
|
-
const pipeName = 'webpack-dev-server.sock';
|
|
228
|
-
|
|
229
|
-
options.ipc = path.join(pipePrefix, pipeName);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
options.liveReload =
|
|
233
|
-
typeof options.liveReload !== 'undefined' ? options.liveReload : true;
|
|
234
|
-
|
|
235
|
-
// https://github.com/webpack/webpack-dev-server/issues/1990
|
|
236
|
-
const defaultOpenOptions = { wait: false };
|
|
237
|
-
const getOpenItemsFromObject = ({ target, ...rest }) => {
|
|
238
|
-
const normalizedOptions = { ...defaultOpenOptions, ...rest };
|
|
239
|
-
|
|
240
|
-
if (typeof normalizedOptions.app === 'string') {
|
|
241
|
-
normalizedOptions.app = {
|
|
242
|
-
name: normalizedOptions.app,
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const normalizedTarget = typeof target === 'undefined' ? '<url>' : target;
|
|
247
|
-
|
|
248
|
-
if (Array.isArray(normalizedTarget)) {
|
|
249
|
-
return normalizedTarget.map((singleTarget) => {
|
|
250
|
-
return { target: singleTarget, options: normalizedOptions };
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return [{ target: normalizedTarget, options: normalizedOptions }];
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
if (typeof options.open === 'undefined') {
|
|
258
|
-
options.open = [];
|
|
259
|
-
} else if (typeof options.open === 'boolean') {
|
|
260
|
-
options.open = options.open
|
|
261
|
-
? [{ target: '<url>', options: defaultOpenOptions }]
|
|
262
|
-
: [];
|
|
263
|
-
} else if (typeof options.open === 'string') {
|
|
264
|
-
options.open = [{ target: options.open, options: defaultOpenOptions }];
|
|
265
|
-
} else if (Array.isArray(options.open)) {
|
|
266
|
-
const result = [];
|
|
267
|
-
|
|
268
|
-
options.open.forEach((item) => {
|
|
269
|
-
if (typeof item === 'string') {
|
|
270
|
-
result.push({ target: item, options: defaultOpenOptions });
|
|
271
|
-
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
result.push(...getOpenItemsFromObject(item));
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
options.open = result;
|
|
279
|
-
} else {
|
|
280
|
-
options.open = [...getOpenItemsFromObject(options.open)];
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (typeof options.port === 'string' && options.port !== 'auto') {
|
|
284
|
-
options.port = Number(options.port);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Assume a proxy configuration specified as:
|
|
289
|
-
* proxy: {
|
|
290
|
-
* 'context': { options }
|
|
291
|
-
* }
|
|
292
|
-
* OR
|
|
293
|
-
* proxy: {
|
|
294
|
-
* 'context': 'target'
|
|
295
|
-
* }
|
|
296
|
-
*/
|
|
297
|
-
if (typeof options.proxy !== 'undefined') {
|
|
298
|
-
if (!Array.isArray(options.proxy)) {
|
|
299
|
-
if (Object.prototype.hasOwnProperty.call(options.proxy, 'target')) {
|
|
300
|
-
options.proxy = [options.proxy];
|
|
301
|
-
} else {
|
|
302
|
-
options.proxy = Object.keys(options.proxy).map((context) => {
|
|
303
|
-
let proxyOptions;
|
|
304
|
-
// For backwards compatibility reasons.
|
|
305
|
-
const correctedContext = context
|
|
306
|
-
.replace(/^\*$/, '**')
|
|
307
|
-
.replace(/\/\*$/, '');
|
|
308
|
-
|
|
309
|
-
if (typeof options.proxy[context] === 'string') {
|
|
310
|
-
proxyOptions = {
|
|
311
|
-
context: correctedContext,
|
|
312
|
-
target: options.proxy[context],
|
|
313
|
-
};
|
|
314
|
-
} else {
|
|
315
|
-
proxyOptions = { ...options.proxy[context] };
|
|
316
|
-
proxyOptions.context = correctedContext;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const getLogLevelForProxy = (level) => {
|
|
320
|
-
if (level === 'none') {
|
|
321
|
-
return 'silent';
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (level === 'log') {
|
|
325
|
-
return 'info';
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (level === 'verbose') {
|
|
329
|
-
return 'debug';
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return level;
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
const configs = getCompilerConfigArray(compiler);
|
|
336
|
-
const configWithDevServer =
|
|
337
|
-
configs.find((config) => config.devServer) || configs[0];
|
|
338
|
-
|
|
339
|
-
if (typeof proxyOptions.logLevel === 'undefined') {
|
|
340
|
-
proxyOptions.logLevel = getLogLevelForProxy(
|
|
341
|
-
configWithDevServer.infrastructureLogging.level
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
if (typeof proxyOptions.logProvider === 'undefined') {
|
|
346
|
-
proxyOptions.logProvider = () => logger;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return proxyOptions;
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if (typeof options.setupExitSignals === 'undefined') {
|
|
356
|
-
options.setupExitSignals = true;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (typeof options.static === 'undefined') {
|
|
360
|
-
options.static = [defaultOptionsForStatic];
|
|
361
|
-
} else if (typeof options.static === 'boolean') {
|
|
362
|
-
options.static = options.static ? [defaultOptionsForStatic] : false;
|
|
363
|
-
} else if (typeof options.static === 'string') {
|
|
364
|
-
options.static = [
|
|
365
|
-
{ ...defaultOptionsForStatic, directory: options.static },
|
|
366
|
-
];
|
|
367
|
-
} else if (Array.isArray(options.static)) {
|
|
368
|
-
options.static = options.static.map((item) => {
|
|
369
|
-
if (typeof item === 'string') {
|
|
370
|
-
return { ...defaultOptionsForStatic, directory: item };
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
return { ...defaultOptionsForStatic, ...item };
|
|
374
|
-
});
|
|
375
|
-
} else {
|
|
376
|
-
options.static = [{ ...defaultOptionsForStatic, ...options.static }];
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (options.static) {
|
|
380
|
-
const isAbsoluteUrl = require('is-absolute-url');
|
|
381
|
-
|
|
382
|
-
options.static.forEach((staticOption) => {
|
|
383
|
-
if (isAbsoluteUrl(staticOption.directory)) {
|
|
384
|
-
throw new Error('Using a URL as static.directory is not supported');
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// ensure that publicPath is an array
|
|
388
|
-
if (typeof staticOption.publicPath === 'string') {
|
|
389
|
-
staticOption.publicPath = [staticOption.publicPath];
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// ensure that watch is an object if true
|
|
393
|
-
if (staticOption.watch === true) {
|
|
394
|
-
staticOption.watch = defaultOptionsForStatic.watch;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// ensure that serveIndex is an object if true
|
|
398
|
-
if (staticOption.serveIndex === true) {
|
|
399
|
-
staticOption.serveIndex = defaultOptionsForStatic.serveIndex;
|
|
400
|
-
}
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
const defaultWebSocketServerType = 'ws';
|
|
405
|
-
const defaultWebSocketServerOptions = { path: '/ws' };
|
|
406
|
-
|
|
407
|
-
if (typeof options.webSocketServer === 'undefined') {
|
|
408
|
-
options.webSocketServer = {
|
|
409
|
-
type: defaultWebSocketServerType,
|
|
410
|
-
options: defaultWebSocketServerOptions,
|
|
411
|
-
};
|
|
412
|
-
} else if (
|
|
413
|
-
typeof options.webSocketServer === 'boolean' &&
|
|
414
|
-
!options.webSocketServer
|
|
415
|
-
) {
|
|
416
|
-
options.webSocketServer = false;
|
|
417
|
-
} else if (
|
|
418
|
-
typeof options.webSocketServer === 'string' ||
|
|
419
|
-
typeof options.webSocketServer === 'function'
|
|
420
|
-
) {
|
|
421
|
-
options.webSocketServer = {
|
|
422
|
-
type: options.webSocketServer,
|
|
423
|
-
options: defaultWebSocketServerOptions,
|
|
424
|
-
};
|
|
425
|
-
} else {
|
|
426
|
-
options.webSocketServer = {
|
|
427
|
-
type: options.webSocketServer.type || defaultWebSocketServerType,
|
|
428
|
-
options: {
|
|
429
|
-
...defaultWebSocketServerOptions,
|
|
430
|
-
...options.webSocketServer.options,
|
|
431
|
-
},
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
if (typeof options.webSocketServer.options.port === 'string') {
|
|
435
|
-
options.webSocketServer.options.port = Number(
|
|
436
|
-
options.webSocketServer.options.port
|
|
437
|
-
);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
module.exports = normalizeOptions;
|