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.
@@ -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;