webpack-dev-server 4.5.0 → 4.6.0

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 CHANGED
@@ -121,7 +121,7 @@ Options:
121
121
  --no-hot Disables Hot Module Replacement.
122
122
  --http2 Allows to serve over HTTP/2 using SPDY. Deprecated, it will be removed in favor of the `server` option.
123
123
  --no-http2 Does not serve over HTTP/2 using SPDY.
124
- --https Allows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP). Deprecated, it will be removed in favor
124
+ --https Allows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP). Deprecated, it will be removed in favor
125
125
  of the `server` option.
126
126
  --no-https Disallows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP).
127
127
  --https-passphrase <value> Passphrase for a pfx file. Deprecated, it will be removed in favor of the `server.options.passphrase` option.
@@ -269,7 +269,7 @@ Pull Request to resolve the bug.
269
269
 
270
270
  ## Support
271
271
 
272
- We do our best to keep Issues in the repository focused on bugs, features, and
272
+ We do our best to keep issues in the repository focused on bugs, features, and
273
273
  needed modifications to the code for the module. Because of that, we ask users
274
274
  with general support, "how-to", or "why isn't this working" questions to try one
275
275
  of the other support channels that are available.
package/client/index.js CHANGED
@@ -135,7 +135,7 @@ var onSocketMessage = {
135
135
  log.info("".concat(file ? "\"".concat(file, "\"") : "Content", " from static directory was changed. Reloading..."));
136
136
  self.location.reload();
137
137
  },
138
- warnings: function warnings(_warnings) {
138
+ warnings: function warnings(_warnings, params) {
139
139
  log.warn("Warnings while compiling.");
140
140
 
141
141
  var printableWarnings = _warnings.map(function (error) {
@@ -157,6 +157,12 @@ var onSocketMessage = {
157
157
  if (needShowOverlayForWarnings) {
158
158
  show("warning", _warnings);
159
159
  }
160
+
161
+ if (params && params.preventReloading) {
162
+ return;
163
+ }
164
+
165
+ reloadApp(options, status);
160
166
  },
161
167
  errors: function errors(_errors) {
162
168
  log.error("Errors while compiling. Reload prevented.");
package/client/socket.js CHANGED
@@ -35,7 +35,7 @@ var socket = function initSocket(url, handlers, reconnect) {
35
35
  retries += 1;
36
36
  log.info("Trying to reconnect...");
37
37
  setTimeout(function () {
38
- socket(url, handlers);
38
+ socket(url, handlers, reconnect);
39
39
  }, retryInMs);
40
40
  }
41
41
  });
@@ -43,7 +43,7 @@ var socket = function initSocket(url, handlers, reconnect) {
43
43
  var message = JSON.parse(data);
44
44
 
45
45
  if (handlers[message.type]) {
46
- handlers[message.type](message.data);
46
+ handlers[message.type](message.data, message.params);
47
47
  }
48
48
  });
49
49
  };
package/lib/Server.js CHANGED
@@ -6,7 +6,7 @@ const url = require("url");
6
6
  const util = require("util");
7
7
  const fs = require("graceful-fs");
8
8
  const ipaddr = require("ipaddr.js");
9
- const internalIp = require("internal-ip");
9
+ const defaultGateway = require("default-gateway");
10
10
  const express = require("express");
11
11
  const { validate } = require("schema-utils");
12
12
  const schema = require("./options.json");
@@ -50,7 +50,6 @@ class Server {
50
50
  };
51
51
  }
52
52
 
53
- // eslint-disable-next-line class-methods-use-this
54
53
  static isAbsoluteURL(URL) {
55
54
  // Don't match Windows paths `c:\`
56
55
  if (/^[a-zA-Z]:\\/.test(URL)) {
@@ -62,13 +61,54 @@ class Server {
62
61
  return /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(URL);
63
62
  }
64
63
 
64
+ static findIp(gateway) {
65
+ const gatewayIp = ipaddr.parse(gateway);
66
+
67
+ // Look for the matching interface in all local interfaces.
68
+ for (const addresses of Object.values(os.networkInterfaces())) {
69
+ for (const { cidr } of addresses) {
70
+ const net = ipaddr.parseCIDR(cidr);
71
+
72
+ if (
73
+ net[0] &&
74
+ net[0].kind() === gatewayIp.kind() &&
75
+ gatewayIp.match(net)
76
+ ) {
77
+ return net[0].toString();
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ static async internalIP(family) {
84
+ try {
85
+ const { gateway } = await defaultGateway[family]();
86
+ return Server.findIp(gateway);
87
+ } catch {
88
+ // ignore
89
+ }
90
+ }
91
+
92
+ static internalIPSync(family) {
93
+ try {
94
+ const { gateway } = defaultGateway[family].sync();
95
+ return Server.findIp(gateway);
96
+ } catch {
97
+ // ignore
98
+ }
99
+ }
100
+
65
101
  static async getHostname(hostname) {
66
102
  if (hostname === "local-ip") {
67
- return (await internalIp.v4()) || (await internalIp.v6()) || "0.0.0.0";
103
+ return (
104
+ (await Server.internalIP("v4")) ||
105
+ (await Server.internalIP("v6")) ||
106
+ "0.0.0.0"
107
+ );
68
108
  } else if (hostname === "local-ipv4") {
69
- return (await internalIp.v4()) || "0.0.0.0";
109
+ return (await Server.internalIP("v4")) || "0.0.0.0";
70
110
  } else if (hostname === "local-ipv6") {
71
- return (await internalIp.v6()) || "::";
111
+ return (await Server.internalIP("v6")) || "::";
72
112
  }
73
113
 
74
114
  return hostname;
@@ -395,7 +435,6 @@ class Server {
395
435
  return this.compiler.options;
396
436
  }
397
437
 
398
- // eslint-disable-next-line class-methods-use-this
399
438
  async normalizeOptions() {
400
439
  const { options } = this;
401
440
 
@@ -405,14 +444,125 @@ class Server {
405
444
 
406
445
  const compilerOptions = this.getCompilerOptions();
407
446
  // TODO remove `{}` after drop webpack v4 support
408
- const watchOptions = compilerOptions.watchOptions || {};
409
- const defaultOptionsForStatic = {
410
- directory: path.join(process.cwd(), "public"),
411
- staticOptions: {},
412
- publicPath: ["/"],
413
- serveIndex: { icons: true },
414
- // Respect options from compiler watchOptions
415
- watch: watchOptions,
447
+ const compilerWatchOptions = compilerOptions.watchOptions || {};
448
+ const getWatchOptions = (watchOptions = {}) => {
449
+ const getPolling = () => {
450
+ if (typeof watchOptions.usePolling !== "undefined") {
451
+ return watchOptions.usePolling;
452
+ }
453
+
454
+ if (typeof watchOptions.poll !== "undefined") {
455
+ return Boolean(watchOptions.poll);
456
+ }
457
+
458
+ if (typeof compilerWatchOptions.poll !== "undefined") {
459
+ return Boolean(compilerWatchOptions.poll);
460
+ }
461
+
462
+ return false;
463
+ };
464
+ const getInterval = () => {
465
+ if (typeof watchOptions.interval !== "undefined") {
466
+ return watchOptions.interval;
467
+ }
468
+
469
+ if (typeof watchOptions.poll === "number") {
470
+ return watchOptions.poll;
471
+ }
472
+
473
+ if (typeof compilerWatchOptions.poll === "number") {
474
+ return compilerWatchOptions.poll;
475
+ }
476
+ };
477
+
478
+ const usePolling = getPolling();
479
+ const interval = getInterval();
480
+ const { poll, ...rest } = watchOptions;
481
+
482
+ return {
483
+ ignoreInitial: true,
484
+ persistent: true,
485
+ followSymlinks: false,
486
+ atomic: false,
487
+ alwaysStat: true,
488
+ ignorePermissionErrors: true,
489
+ // Respect options from compiler watchOptions
490
+ usePolling,
491
+ interval,
492
+ ignored: watchOptions.ignored,
493
+ // TODO: we respect these options for all watch options and allow developers to pass them to chokidar, but chokidar doesn't have these options maybe we need revisit that in future
494
+ ...rest,
495
+ };
496
+ };
497
+ const getStaticItem = (optionsForStatic) => {
498
+ const getDefaultStaticOptions = () => {
499
+ return {
500
+ directory: path.join(process.cwd(), "public"),
501
+ staticOptions: {},
502
+ publicPath: ["/"],
503
+ serveIndex: { icons: true },
504
+ watch: getWatchOptions(),
505
+ };
506
+ };
507
+
508
+ let item;
509
+
510
+ if (typeof optionsForStatic === "undefined") {
511
+ item = getDefaultStaticOptions();
512
+ } else if (typeof optionsForStatic === "string") {
513
+ item = {
514
+ ...getDefaultStaticOptions(),
515
+ directory: optionsForStatic,
516
+ };
517
+ } else {
518
+ const def = getDefaultStaticOptions();
519
+
520
+ item = {
521
+ directory:
522
+ typeof optionsForStatic.directory !== "undefined"
523
+ ? optionsForStatic.directory
524
+ : def.directory,
525
+ // TODO: do merge in the next major release
526
+ staticOptions:
527
+ typeof optionsForStatic.staticOptions !== "undefined"
528
+ ? optionsForStatic.staticOptions
529
+ : def.staticOptions,
530
+ publicPath:
531
+ typeof optionsForStatic.publicPath !== "undefined"
532
+ ? optionsForStatic.publicPath
533
+ : def.publicPath,
534
+ // TODO: do merge in the next major release
535
+ serveIndex:
536
+ // eslint-disable-next-line no-nested-ternary
537
+ typeof optionsForStatic.serveIndex !== "undefined"
538
+ ? typeof optionsForStatic.serveIndex === "boolean" &&
539
+ optionsForStatic.serveIndex
540
+ ? def.serveIndex
541
+ : optionsForStatic.serveIndex
542
+ : def.serveIndex,
543
+ watch:
544
+ // eslint-disable-next-line no-nested-ternary
545
+ typeof optionsForStatic.watch !== "undefined"
546
+ ? // eslint-disable-next-line no-nested-ternary
547
+ typeof optionsForStatic.watch === "boolean"
548
+ ? optionsForStatic.watch
549
+ ? def.watch
550
+ : false
551
+ : getWatchOptions(optionsForStatic.watch)
552
+ : def.watch,
553
+ };
554
+ }
555
+
556
+ if (Server.isAbsoluteURL(item.directory)) {
557
+ throw new Error("Using a URL as static.directory is not supported");
558
+ }
559
+
560
+ // ensure that publicPath is an array
561
+ if (typeof item.publicPath === "string") {
562
+ item.publicPath = [item.publicPath];
563
+ }
564
+
565
+ return item;
416
566
  };
417
567
 
418
568
  if (typeof options.allowedHosts === "undefined") {
@@ -882,50 +1032,27 @@ class Server {
882
1032
  }
883
1033
 
884
1034
  if (typeof options.static === "undefined") {
885
- options.static = [defaultOptionsForStatic];
1035
+ options.static = [getStaticItem()];
886
1036
  } else if (typeof options.static === "boolean") {
887
- options.static = options.static ? [defaultOptionsForStatic] : false;
1037
+ options.static = options.static ? [getStaticItem()] : false;
888
1038
  } else if (typeof options.static === "string") {
889
- options.static = [
890
- { ...defaultOptionsForStatic, directory: options.static },
891
- ];
1039
+ options.static = [getStaticItem(options.static)];
892
1040
  } else if (Array.isArray(options.static)) {
893
1041
  options.static = options.static.map((item) => {
894
1042
  if (typeof item === "string") {
895
- return { ...defaultOptionsForStatic, directory: item };
1043
+ return getStaticItem(item);
896
1044
  }
897
1045
 
898
- return { ...defaultOptionsForStatic, ...item };
1046
+ return getStaticItem(item);
899
1047
  });
900
1048
  } else {
901
- options.static = [{ ...defaultOptionsForStatic, ...options.static }];
902
- }
903
-
904
- if (options.static) {
905
- options.static.forEach((staticOption) => {
906
- if (Server.isAbsoluteURL(staticOption.directory)) {
907
- throw new Error("Using a URL as static.directory is not supported");
908
- }
909
-
910
- // ensure that publicPath is an array
911
- if (typeof staticOption.publicPath === "string") {
912
- staticOption.publicPath = [staticOption.publicPath];
913
- }
914
-
915
- // ensure that watch is an object if true
916
- if (staticOption.watch === true) {
917
- staticOption.watch = defaultOptionsForStatic.watch;
918
- }
919
-
920
- // ensure that serveIndex is an object if true
921
- if (staticOption.serveIndex === true) {
922
- staticOption.serveIndex = defaultOptionsForStatic.serveIndex;
923
- }
924
- });
1049
+ options.static = [getStaticItem(options.static)];
925
1050
  }
926
1051
 
927
1052
  if (typeof options.watchFiles === "string") {
928
- options.watchFiles = [{ paths: options.watchFiles, options: {} }];
1053
+ options.watchFiles = [
1054
+ { paths: options.watchFiles, options: getWatchOptions() },
1055
+ ];
929
1056
  } else if (
930
1057
  typeof options.watchFiles === "object" &&
931
1058
  options.watchFiles !== null &&
@@ -934,16 +1061,19 @@ class Server {
934
1061
  options.watchFiles = [
935
1062
  {
936
1063
  paths: options.watchFiles.paths,
937
- options: options.watchFiles.options || {},
1064
+ options: getWatchOptions(options.watchFiles.options || {}),
938
1065
  },
939
1066
  ];
940
1067
  } else if (Array.isArray(options.watchFiles)) {
941
1068
  options.watchFiles = options.watchFiles.map((item) => {
942
1069
  if (typeof item === "string") {
943
- return { paths: item, options: {} };
1070
+ return { paths: item, options: getWatchOptions() };
944
1071
  }
945
1072
 
946
- return { paths: item.paths, options: item.options || {} };
1073
+ return {
1074
+ paths: item.paths,
1075
+ options: getWatchOptions(item.options || {}),
1076
+ };
947
1077
  });
948
1078
  } else {
949
1079
  options.watchFiles = [];
@@ -1118,7 +1248,6 @@ class Server {
1118
1248
  if (this.options.webSocketServer) {
1119
1249
  const compilers = this.compiler.compilers || [this.compiler];
1120
1250
 
1121
- // eslint-disable-next-line no-shadow
1122
1251
  compilers.forEach((compiler) => {
1123
1252
  this.addAdditionalEntries(compiler);
1124
1253
 
@@ -1814,13 +1943,13 @@ class Server {
1814
1943
  if (parsedIP.range() === "unspecified") {
1815
1944
  localhost = prettyPrintURL("localhost");
1816
1945
 
1817
- const networkIPv4 = internalIp.v4.sync();
1946
+ const networkIPv4 = Server.internalIPSync("v4");
1818
1947
 
1819
1948
  if (networkIPv4) {
1820
1949
  networkUrlIPv4 = prettyPrintURL(networkIPv4);
1821
1950
  }
1822
1951
 
1823
- const networkIPv6 = internalIp.v6.sync();
1952
+ const networkIPv6 = Server.internalIPSync("v6");
1824
1953
 
1825
1954
  if (networkIPv6) {
1826
1955
  networkUrlIPv6 = prettyPrintURL(networkIPv6);
@@ -2019,12 +2148,12 @@ class Server {
2019
2148
  }
2020
2149
 
2021
2150
  // eslint-disable-next-line class-methods-use-this
2022
- sendMessage(clients, type, data) {
2151
+ sendMessage(clients, type, data, params) {
2023
2152
  for (const client of clients) {
2024
2153
  // `sockjs` uses `1` to indicate client is ready to accept data
2025
2154
  // `ws` uses `WebSocket.OPEN`, but it is mean `1` too
2026
2155
  if (client.readyState === 1) {
2027
- client.send(JSON.stringify({ type, data }));
2156
+ client.send(JSON.stringify({ type, data, params }));
2028
2157
  }
2029
2158
  }
2030
2159
  }
@@ -2073,8 +2202,16 @@ class Server {
2073
2202
  this.sendMessage(clients, "hash", stats.hash);
2074
2203
 
2075
2204
  if (stats.errors.length > 0 || stats.warnings.length > 0) {
2205
+ const hasErrors = stats.errors.length > 0;
2206
+
2076
2207
  if (stats.warnings.length > 0) {
2077
- this.sendMessage(clients, "warnings", stats.warnings);
2208
+ let params;
2209
+
2210
+ if (hasErrors) {
2211
+ params = { preventReloading: true };
2212
+ }
2213
+
2214
+ this.sendMessage(clients, "warnings", stats.warnings, params);
2078
2215
  }
2079
2216
 
2080
2217
  if (stats.errors.length > 0) {
@@ -2086,37 +2223,8 @@ class Server {
2086
2223
  }
2087
2224
 
2088
2225
  watchFiles(watchPath, watchOptions) {
2089
- // duplicate the same massaging of options that watchpack performs
2090
- // https://github.com/webpack/watchpack/blob/master/lib/DirectoryWatcher.js#L49
2091
- // this isn't an elegant solution, but we'll improve it in the future
2092
- // eslint-disable-next-line no-undefined
2093
- const usePolling =
2094
- typeof watchOptions.usePolling !== "undefined"
2095
- ? watchOptions.usePolling
2096
- : Boolean(watchOptions.poll);
2097
- const interval =
2098
- // eslint-disable-next-line no-nested-ternary
2099
- typeof watchOptions.interval !== "undefined"
2100
- ? watchOptions.interval
2101
- : typeof watchOptions.poll === "number"
2102
- ? watchOptions.poll
2103
- : // eslint-disable-next-line no-undefined
2104
- undefined;
2105
-
2106
- const finalWatchOptions = {
2107
- ignoreInitial: true,
2108
- persistent: true,
2109
- followSymlinks: false,
2110
- atomic: false,
2111
- alwaysStat: true,
2112
- ignorePermissionErrors: true,
2113
- ignored: watchOptions.ignored,
2114
- usePolling,
2115
- interval,
2116
- };
2117
-
2118
2226
  const chokidar = require("chokidar");
2119
- const watcher = chokidar.watch(watchPath, finalWatchOptions);
2227
+ const watcher = chokidar.watch(watchPath, watchOptions);
2120
2228
 
2121
2229
  // disabling refreshing on changing the content
2122
2230
  if (this.options.liveReload) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webpack-dev-server",
3
- "version": "4.5.0",
3
+ "version": "4.6.0",
4
4
  "description": "Serves a webpack app. Updates the browser on changes.",
5
5
  "bin": "bin/webpack-dev-server.js",
6
6
  "main": "lib/Server.js",
@@ -38,17 +38,17 @@
38
38
  "colorette": "^2.0.10",
39
39
  "compression": "^1.7.4",
40
40
  "connect-history-api-fallback": "^1.6.0",
41
+ "default-gateway": "^6.0.3",
41
42
  "del": "^6.0.0",
42
43
  "express": "^4.17.1",
43
44
  "graceful-fs": "^4.2.6",
44
45
  "html-entities": "^2.3.2",
45
46
  "http-proxy-middleware": "^2.0.0",
46
- "internal-ip": "^6.2.0",
47
47
  "ipaddr.js": "^2.0.1",
48
48
  "open": "^8.0.9",
49
49
  "p-retry": "^4.5.0",
50
50
  "portfinder": "^1.0.28",
51
- "schema-utils": "^3.1.0",
51
+ "schema-utils": "^4.0.0",
52
52
  "selfsigned": "^1.10.11",
53
53
  "serve-index": "^1.9.1",
54
54
  "sockjs": "^0.3.21",
@@ -66,16 +66,14 @@
66
66
  "@babel/plugin-transform-runtime": "^7.14.5",
67
67
  "@babel/preset-env": "^7.14.5",
68
68
  "@babel/runtime": "^7.14.5",
69
- "@commitlint/cli": "^14.1.0",
70
- "@commitlint/config-conventional": "^14.1.0",
69
+ "@commitlint/cli": "^15.0.0",
70
+ "@commitlint/config-conventional": "^15.0.0",
71
71
  "acorn": "^8.2.4",
72
72
  "babel-jest": "^27.0.2",
73
73
  "babel-loader": "^8.2.2",
74
74
  "body-parser": "^1.19.0",
75
75
  "core-js": "^3.12.1",
76
76
  "css-loader": "^5.2.4",
77
- "css-tree": "^1.1.3",
78
- "csstree": "^0.0.3",
79
77
  "eslint": "^8.0.1",
80
78
  "eslint-config-prettier": "^8.3.0",
81
79
  "eslint-config-webpack": "^1.2.5",
@@ -89,12 +87,12 @@
89
87
  "klona": "^2.0.4",
90
88
  "less": "^4.1.1",
91
89
  "less-loader": "^7.3.0",
92
- "lint-staged": "^11.0.0",
90
+ "lint-staged": "^12.0.2",
93
91
  "marked": "^3.0.0",
94
92
  "memfs": "^3.2.2",
95
93
  "npm-run-all": "^4.1.5",
96
94
  "prettier": "^2.3.1",
97
- "puppeteer": "^10.0.0",
95
+ "puppeteer": "^11.0.0",
98
96
  "require-from-string": "^2.0.2",
99
97
  "rimraf": "^3.0.2",
100
98
  "sockjs-client": "^1.5.1",