webpack-dev-server 4.2.1 → 4.5.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 +65 -17
- package/bin/cli-flags.js +317 -35
- package/client/index.js +34 -18
- package/client/modules/logger/index.js +43 -14
- package/client/modules/sockjs-client/index.js +20 -17
- package/client/overlay.js +30 -5
- package/client/socket.js +7 -3
- package/lib/Server.js +202 -105
- package/lib/options.json +282 -17
- package/package.json +10 -8
package/lib/Server.js
CHANGED
|
@@ -32,17 +32,18 @@ class Server {
|
|
|
32
32
|
|
|
33
33
|
this.options = options;
|
|
34
34
|
this.staticWatchers = [];
|
|
35
|
+
this.listeners = [];
|
|
35
36
|
// Keep track of websocket proxies for external websocket upgrade.
|
|
36
37
|
this.webSocketProxies = [];
|
|
37
38
|
this.sockets = [];
|
|
38
39
|
this.compiler = compiler;
|
|
40
|
+
this.currentHash = null;
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
static get DEFAULT_STATS() {
|
|
42
44
|
return {
|
|
43
45
|
all: false,
|
|
44
46
|
hash: true,
|
|
45
|
-
assets: true,
|
|
46
47
|
warnings: true,
|
|
47
48
|
errors: true,
|
|
48
49
|
errorDetails: false,
|
|
@@ -74,7 +75,7 @@ class Server {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
static async getFreePort(port) {
|
|
77
|
-
if (port && port !== "auto") {
|
|
78
|
+
if (typeof port !== "undefined" && port !== null && port !== "auto") {
|
|
78
79
|
return port;
|
|
79
80
|
}
|
|
80
81
|
|
|
@@ -155,7 +156,7 @@ class Server {
|
|
|
155
156
|
if (typeof this.options.client.webSocketURL.protocol !== "undefined") {
|
|
156
157
|
protocol = this.options.client.webSocketURL.protocol;
|
|
157
158
|
} else {
|
|
158
|
-
protocol = this.options.
|
|
159
|
+
protocol = this.options.server.type === "http" ? "ws:" : "wss:";
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
searchParams.set("protocol", protocol);
|
|
@@ -258,6 +259,10 @@ class Server {
|
|
|
258
259
|
searchParams.set("logging", this.options.client.logging);
|
|
259
260
|
}
|
|
260
261
|
|
|
262
|
+
if (typeof this.options.client.reconnect !== "undefined") {
|
|
263
|
+
searchParams.set("reconnect", this.options.client.reconnect);
|
|
264
|
+
}
|
|
265
|
+
|
|
261
266
|
webSocketURL = searchParams.toString();
|
|
262
267
|
}
|
|
263
268
|
|
|
@@ -474,6 +479,14 @@ class Server {
|
|
|
474
479
|
};
|
|
475
480
|
}
|
|
476
481
|
|
|
482
|
+
if (typeof options.client.reconnect === "undefined") {
|
|
483
|
+
options.client.reconnect = 10;
|
|
484
|
+
} else if (options.client.reconnect === true) {
|
|
485
|
+
options.client.reconnect = Infinity;
|
|
486
|
+
} else if (options.client.reconnect === false) {
|
|
487
|
+
options.client.reconnect = 0;
|
|
488
|
+
}
|
|
489
|
+
|
|
477
490
|
// Respect infrastructureLogging.level
|
|
478
491
|
if (typeof options.client.logging === "undefined") {
|
|
479
492
|
options.client.logging = compilerOptions.infrastructureLogging
|
|
@@ -508,23 +521,62 @@ class Server {
|
|
|
508
521
|
? options.hot
|
|
509
522
|
: true;
|
|
510
523
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
524
|
+
const isHTTPs = Boolean(options.https);
|
|
525
|
+
const isSPDY = Boolean(options.http2);
|
|
526
|
+
|
|
527
|
+
if (isHTTPs || isSPDY) {
|
|
528
|
+
// TODO: remove in the next major release
|
|
529
|
+
util.deprecate(
|
|
530
|
+
() => {},
|
|
531
|
+
`'${
|
|
532
|
+
isHTTPs ? "https" : "http2"
|
|
533
|
+
}' option is deprecated. Please use the 'server' option.`,
|
|
534
|
+
`DEP_WEBPACK_DEV_SERVER_${isHTTPs ? "HTTPS" : "HTTP2"}`
|
|
535
|
+
)();
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
options.server = {
|
|
539
|
+
type:
|
|
540
|
+
// eslint-disable-next-line no-nested-ternary
|
|
541
|
+
typeof options.server === "string"
|
|
542
|
+
? options.server
|
|
543
|
+
: // eslint-disable-next-line no-nested-ternary
|
|
544
|
+
typeof (options.server || {}).type === "string"
|
|
545
|
+
? options.server.type
|
|
546
|
+
: // eslint-disable-next-line no-nested-ternary
|
|
547
|
+
isSPDY
|
|
548
|
+
? "spdy"
|
|
549
|
+
: isHTTPs
|
|
550
|
+
? "https"
|
|
551
|
+
: "http",
|
|
552
|
+
options: {
|
|
553
|
+
...options.https,
|
|
554
|
+
...(options.server || {}).options,
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
if (
|
|
559
|
+
options.server.type === "spdy" &&
|
|
560
|
+
typeof options.server.options.spdy === "undefined"
|
|
561
|
+
) {
|
|
562
|
+
options.server.options.spdy = {
|
|
563
|
+
protocols: ["h2", "http/1.1"],
|
|
515
564
|
};
|
|
516
565
|
}
|
|
517
566
|
|
|
518
|
-
|
|
519
|
-
|
|
567
|
+
if (options.server.type === "https" || options.server.type === "spdy") {
|
|
568
|
+
if (typeof options.server.options.requestCert === "undefined") {
|
|
569
|
+
options.server.options.requestCert = false;
|
|
570
|
+
}
|
|
571
|
+
|
|
520
572
|
// TODO remove the `cacert` option in favor `ca` in the next major release
|
|
521
573
|
for (const property of ["cacert", "ca", "cert", "crl", "key", "pfx"]) {
|
|
522
|
-
if (typeof options.
|
|
574
|
+
if (typeof options.server.options[property] === "undefined") {
|
|
523
575
|
// eslint-disable-next-line no-continue
|
|
524
576
|
continue;
|
|
525
577
|
}
|
|
526
578
|
|
|
527
|
-
const value = options.
|
|
579
|
+
const value = options.server.options[property];
|
|
528
580
|
const readFile = (item) => {
|
|
529
581
|
if (
|
|
530
582
|
Buffer.isBuffer(item) ||
|
|
@@ -547,14 +599,14 @@ class Server {
|
|
|
547
599
|
}
|
|
548
600
|
};
|
|
549
601
|
|
|
550
|
-
options.
|
|
602
|
+
options.server.options[property] = Array.isArray(value)
|
|
551
603
|
? value.map((item) => readFile(item))
|
|
552
604
|
: readFile(value);
|
|
553
605
|
}
|
|
554
606
|
|
|
555
607
|
let fakeCert;
|
|
556
608
|
|
|
557
|
-
if (!options.
|
|
609
|
+
if (!options.server.options.key || !options.server.options.cert) {
|
|
558
610
|
const certificateDir = Server.findCacheDir();
|
|
559
611
|
const certificatePath = path.join(certificateDir, "server.pem");
|
|
560
612
|
let certificateExists;
|
|
@@ -577,7 +629,7 @@ class Server {
|
|
|
577
629
|
const del = require("del");
|
|
578
630
|
|
|
579
631
|
this.logger.info(
|
|
580
|
-
"SSL
|
|
632
|
+
"SSL certificate is more than 30 days old. Removing..."
|
|
581
633
|
);
|
|
582
634
|
|
|
583
635
|
await del([certificatePath], { force: true });
|
|
@@ -587,7 +639,7 @@ class Server {
|
|
|
587
639
|
}
|
|
588
640
|
|
|
589
641
|
if (!certificateExists) {
|
|
590
|
-
this.logger.info("Generating SSL
|
|
642
|
+
this.logger.info("Generating SSL certificate...");
|
|
591
643
|
|
|
592
644
|
const selfsigned = require("selfsigned");
|
|
593
645
|
const attributes = [{ name: "commonName", value: "localhost" }];
|
|
@@ -669,20 +721,20 @@ class Server {
|
|
|
669
721
|
this.logger.info(`SSL certificate: ${certificatePath}`);
|
|
670
722
|
}
|
|
671
723
|
|
|
672
|
-
if (options.
|
|
673
|
-
if (options.
|
|
724
|
+
if (options.server.options.cacert) {
|
|
725
|
+
if (options.server.options.ca) {
|
|
674
726
|
this.logger.warn(
|
|
675
|
-
"Do not specify '
|
|
727
|
+
"Do not specify 'ca' and 'cacert' options together, the 'ca' option will be used."
|
|
676
728
|
);
|
|
677
729
|
} else {
|
|
678
|
-
options.
|
|
730
|
+
options.server.options.ca = options.server.options.cacert;
|
|
679
731
|
}
|
|
680
732
|
|
|
681
|
-
delete options.
|
|
733
|
+
delete options.server.options.cacert;
|
|
682
734
|
}
|
|
683
735
|
|
|
684
|
-
options.
|
|
685
|
-
options.
|
|
736
|
+
options.server.options.key = options.server.options.key || fakeCert;
|
|
737
|
+
options.server.options.cert = options.server.options.cert || fakeCert;
|
|
686
738
|
}
|
|
687
739
|
|
|
688
740
|
if (typeof options.ipc === "boolean") {
|
|
@@ -1063,42 +1115,43 @@ class Server {
|
|
|
1063
1115
|
}
|
|
1064
1116
|
|
|
1065
1117
|
async initialize() {
|
|
1066
|
-
|
|
1118
|
+
if (this.options.webSocketServer) {
|
|
1119
|
+
const compilers = this.compiler.compilers || [this.compiler];
|
|
1067
1120
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1121
|
+
// eslint-disable-next-line no-shadow
|
|
1122
|
+
compilers.forEach((compiler) => {
|
|
1123
|
+
this.addAdditionalEntries(compiler);
|
|
1071
1124
|
|
|
1072
|
-
|
|
1125
|
+
const webpack = compiler.webpack || require("webpack");
|
|
1073
1126
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1127
|
+
new webpack.ProvidePlugin({
|
|
1128
|
+
__webpack_dev_server_client__: this.getClientTransport(),
|
|
1129
|
+
}).apply(compiler);
|
|
1077
1130
|
|
|
1078
|
-
|
|
1131
|
+
// TODO remove after drop webpack v4 support
|
|
1132
|
+
compiler.options.plugins = compiler.options.plugins || [];
|
|
1079
1133
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1134
|
+
if (this.options.hot) {
|
|
1135
|
+
const HMRPluginExists = compiler.options.plugins.find(
|
|
1136
|
+
(p) => p.constructor === webpack.HotModuleReplacementPlugin
|
|
1137
|
+
);
|
|
1082
1138
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1139
|
+
if (HMRPluginExists) {
|
|
1140
|
+
this.logger.warn(
|
|
1141
|
+
`"hot: true" automatically applies HMR plugin, you don't have to add it manually to your webpack configuration.`
|
|
1142
|
+
);
|
|
1143
|
+
} else {
|
|
1144
|
+
// Apply the HMR plugin
|
|
1145
|
+
const plugin = new webpack.HotModuleReplacementPlugin();
|
|
1087
1146
|
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
`"hot: true" automatically applies HMR plugin, you don't have to add it manually to your webpack configuration.`
|
|
1091
|
-
);
|
|
1092
|
-
} else {
|
|
1093
|
-
// apply the HMR plugin
|
|
1094
|
-
const plugin = new webpack.HotModuleReplacementPlugin();
|
|
1095
|
-
plugin.apply(compiler);
|
|
1147
|
+
plugin.apply(compiler);
|
|
1148
|
+
}
|
|
1096
1149
|
}
|
|
1097
|
-
}
|
|
1098
|
-
});
|
|
1150
|
+
});
|
|
1099
1151
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1152
|
+
if (this.options.client && this.options.client.progress) {
|
|
1153
|
+
this.setupProgressPlugin();
|
|
1154
|
+
}
|
|
1102
1155
|
}
|
|
1103
1156
|
|
|
1104
1157
|
this.setupHooks();
|
|
@@ -1114,20 +1167,43 @@ class Server {
|
|
|
1114
1167
|
if (this.options.setupExitSignals) {
|
|
1115
1168
|
const signals = ["SIGINT", "SIGTERM"];
|
|
1116
1169
|
|
|
1170
|
+
let needForceShutdown = false;
|
|
1171
|
+
|
|
1117
1172
|
signals.forEach((signal) => {
|
|
1118
|
-
|
|
1119
|
-
|
|
1173
|
+
const listener = () => {
|
|
1174
|
+
if (needForceShutdown) {
|
|
1120
1175
|
// eslint-disable-next-line no-process-exit
|
|
1121
1176
|
process.exit();
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
this.logger.info(
|
|
1180
|
+
"Gracefully shutting down. To force exit, press ^C again. Please wait..."
|
|
1181
|
+
);
|
|
1182
|
+
|
|
1183
|
+
needForceShutdown = true;
|
|
1184
|
+
|
|
1185
|
+
this.stopCallback(() => {
|
|
1186
|
+
if (typeof this.compiler.close === "function") {
|
|
1187
|
+
this.compiler.close(() => {
|
|
1188
|
+
// eslint-disable-next-line no-process-exit
|
|
1189
|
+
process.exit();
|
|
1190
|
+
});
|
|
1191
|
+
} else {
|
|
1192
|
+
// eslint-disable-next-line no-process-exit
|
|
1193
|
+
process.exit();
|
|
1194
|
+
}
|
|
1122
1195
|
});
|
|
1123
|
-
}
|
|
1196
|
+
};
|
|
1197
|
+
|
|
1198
|
+
this.listeners.push({ name: signal, listener });
|
|
1199
|
+
|
|
1200
|
+
process.on(signal, listener);
|
|
1124
1201
|
});
|
|
1125
1202
|
}
|
|
1126
1203
|
|
|
1127
1204
|
// Proxy WebSocket without the initial http request
|
|
1128
1205
|
// https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade
|
|
1129
|
-
|
|
1130
|
-
this.webSocketProxies.forEach(function (webSocketProxy) {
|
|
1206
|
+
this.webSocketProxies.forEach((webSocketProxy) => {
|
|
1131
1207
|
this.server.on("upgrade", webSocketProxy.upgrade);
|
|
1132
1208
|
}, this);
|
|
1133
1209
|
}
|
|
@@ -1526,28 +1602,11 @@ class Server {
|
|
|
1526
1602
|
}
|
|
1527
1603
|
|
|
1528
1604
|
createServer() {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
...this.options.https,
|
|
1535
|
-
spdy: {
|
|
1536
|
-
protocols: ["h2", "http/1.1"],
|
|
1537
|
-
},
|
|
1538
|
-
},
|
|
1539
|
-
this.app
|
|
1540
|
-
);
|
|
1541
|
-
} else {
|
|
1542
|
-
const https = require("https");
|
|
1543
|
-
|
|
1544
|
-
this.server = https.createServer(this.options.https, this.app);
|
|
1545
|
-
}
|
|
1546
|
-
} else {
|
|
1547
|
-
const http = require("http");
|
|
1548
|
-
|
|
1549
|
-
this.server = http.createServer(this.app);
|
|
1550
|
-
}
|
|
1605
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
1606
|
+
this.server = require(this.options.server.type).createServer(
|
|
1607
|
+
this.options.server.options,
|
|
1608
|
+
this.app
|
|
1609
|
+
);
|
|
1551
1610
|
|
|
1552
1611
|
this.server.on("connection", (socket) => {
|
|
1553
1612
|
// Add socket to list
|
|
@@ -1564,6 +1623,7 @@ class Server {
|
|
|
1564
1623
|
});
|
|
1565
1624
|
}
|
|
1566
1625
|
|
|
1626
|
+
// TODO: remove `--web-socket-server` in favor of `--web-socket-server-type`
|
|
1567
1627
|
createWebSocketServer() {
|
|
1568
1628
|
this.webSocketServer = new (this.getServerTransport())(this);
|
|
1569
1629
|
this.webSocketServer.implementation.on("connection", (client, request) => {
|
|
@@ -1589,7 +1649,9 @@ class Server {
|
|
|
1589
1649
|
) {
|
|
1590
1650
|
this.sendMessage([client], "error", "Invalid Host/Origin header");
|
|
1591
1651
|
|
|
1592
|
-
|
|
1652
|
+
// With https enabled, the sendMessage above is encrypted asynchronously so not yet sent
|
|
1653
|
+
// Terminate would prevent it sending, so use close to allow it to be sent
|
|
1654
|
+
client.close();
|
|
1593
1655
|
|
|
1594
1656
|
return;
|
|
1595
1657
|
}
|
|
@@ -1606,6 +1668,10 @@ class Server {
|
|
|
1606
1668
|
this.sendMessage([client], "progress", this.options.client.progress);
|
|
1607
1669
|
}
|
|
1608
1670
|
|
|
1671
|
+
if (this.options.client && this.options.client.reconnect) {
|
|
1672
|
+
this.sendMessage([client], "reconnect", this.options.client.reconnect);
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1609
1675
|
if (this.options.client && this.options.client.overlay) {
|
|
1610
1676
|
this.sendMessage([client], "overlay", this.options.client.overlay);
|
|
1611
1677
|
}
|
|
@@ -1653,26 +1719,29 @@ class Server {
|
|
|
1653
1719
|
);
|
|
1654
1720
|
}
|
|
1655
1721
|
|
|
1656
|
-
|
|
1657
|
-
|
|
1722
|
+
stopBonjour(callback = () => {}) {
|
|
1723
|
+
this.bonjour.unpublishAll(() => {
|
|
1724
|
+
this.bonjour.destroy();
|
|
1725
|
+
|
|
1726
|
+
if (callback) {
|
|
1727
|
+
callback();
|
|
1728
|
+
}
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1658
1731
|
|
|
1659
|
-
|
|
1732
|
+
runBonjour() {
|
|
1733
|
+
this.bonjour = require("bonjour")();
|
|
1734
|
+
this.bonjour.publish({
|
|
1660
1735
|
name: `Webpack Dev Server ${os.hostname()}:${this.options.port}`,
|
|
1661
1736
|
port: this.options.port,
|
|
1662
|
-
type: this.options.
|
|
1737
|
+
type: this.options.server.type === "http" ? "http" : "https",
|
|
1663
1738
|
subtypes: ["webpack"],
|
|
1664
1739
|
...this.options.bonjour,
|
|
1665
1740
|
});
|
|
1666
|
-
|
|
1667
|
-
process.on("exit", () => {
|
|
1668
|
-
bonjour.unpublishAll(() => {
|
|
1669
|
-
bonjour.destroy();
|
|
1670
|
-
});
|
|
1671
|
-
});
|
|
1672
1741
|
}
|
|
1673
1742
|
|
|
1674
1743
|
logStatus() {
|
|
1675
|
-
const
|
|
1744
|
+
const { isColorSupported, cyan, red } = require("colorette");
|
|
1676
1745
|
|
|
1677
1746
|
const getColorsOption = (compilerOptions) => {
|
|
1678
1747
|
let colorsEnabled;
|
|
@@ -1683,7 +1752,7 @@ class Server {
|
|
|
1683
1752
|
) {
|
|
1684
1753
|
colorsEnabled = compilerOptions.stats;
|
|
1685
1754
|
} else {
|
|
1686
|
-
colorsEnabled =
|
|
1755
|
+
colorsEnabled = isColorSupported;
|
|
1687
1756
|
}
|
|
1688
1757
|
|
|
1689
1758
|
return colorsEnabled;
|
|
@@ -1692,14 +1761,14 @@ class Server {
|
|
|
1692
1761
|
const colors = {
|
|
1693
1762
|
info(useColor, msg) {
|
|
1694
1763
|
if (useColor) {
|
|
1695
|
-
return
|
|
1764
|
+
return cyan(msg);
|
|
1696
1765
|
}
|
|
1697
1766
|
|
|
1698
1767
|
return msg;
|
|
1699
1768
|
},
|
|
1700
1769
|
error(useColor, msg) {
|
|
1701
1770
|
if (useColor) {
|
|
1702
|
-
return
|
|
1771
|
+
return red(msg);
|
|
1703
1772
|
}
|
|
1704
1773
|
|
|
1705
1774
|
return msg;
|
|
@@ -1710,7 +1779,7 @@ class Server {
|
|
|
1710
1779
|
if (this.options.ipc) {
|
|
1711
1780
|
this.logger.info(`Project is running at: "${this.server.address()}"`);
|
|
1712
1781
|
} else {
|
|
1713
|
-
const protocol = this.options.
|
|
1782
|
+
const protocol = this.options.server.type === "http" ? "http" : "https";
|
|
1714
1783
|
const { address, port } = this.server.address();
|
|
1715
1784
|
const prettyPrintURL = (newHostname) =>
|
|
1716
1785
|
url.format({ protocol, hostname: newHostname, port, pathname: "/" });
|
|
@@ -1829,7 +1898,9 @@ class Server {
|
|
|
1829
1898
|
|
|
1830
1899
|
if (this.options.bonjour) {
|
|
1831
1900
|
const bonjourProtocol =
|
|
1832
|
-
this.options.bonjour.type || this.options.
|
|
1901
|
+
this.options.bonjour.type || this.options.server.type === "http"
|
|
1902
|
+
? "http"
|
|
1903
|
+
: "https";
|
|
1833
1904
|
|
|
1834
1905
|
this.logger.info(
|
|
1835
1906
|
`Broadcasting "${bonjourProtocol}" with subtype of "webpack" via ZeroConf DNS (Bonjour)`
|
|
@@ -1845,10 +1916,19 @@ class Server {
|
|
|
1845
1916
|
headers = headers(req, res, this.middleware.context);
|
|
1846
1917
|
}
|
|
1847
1918
|
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1919
|
+
const allHeaders = [];
|
|
1920
|
+
|
|
1921
|
+
if (!Array.isArray(headers)) {
|
|
1922
|
+
// eslint-disable-next-line guard-for-in
|
|
1923
|
+
for (const name in headers) {
|
|
1924
|
+
allHeaders.push({ key: name, value: headers[name] });
|
|
1925
|
+
}
|
|
1926
|
+
headers = allHeaders;
|
|
1851
1927
|
}
|
|
1928
|
+
|
|
1929
|
+
headers.forEach((header) => {
|
|
1930
|
+
res.setHeader(header.key, header.value);
|
|
1931
|
+
});
|
|
1852
1932
|
}
|
|
1853
1933
|
|
|
1854
1934
|
next();
|
|
@@ -1940,13 +2020,13 @@ class Server {
|
|
|
1940
2020
|
|
|
1941
2021
|
// eslint-disable-next-line class-methods-use-this
|
|
1942
2022
|
sendMessage(clients, type, data) {
|
|
1943
|
-
|
|
2023
|
+
for (const client of clients) {
|
|
1944
2024
|
// `sockjs` uses `1` to indicate client is ready to accept data
|
|
1945
2025
|
// `ws` uses `WebSocket.OPEN`, but it is mean `1` too
|
|
1946
2026
|
if (client.readyState === 1) {
|
|
1947
2027
|
client.send(JSON.stringify({ type, data }));
|
|
1948
2028
|
}
|
|
1949
|
-
}
|
|
2029
|
+
}
|
|
1950
2030
|
}
|
|
1951
2031
|
|
|
1952
2032
|
serveMagicHtml(req, res, next) {
|
|
@@ -1981,8 +2061,7 @@ class Server {
|
|
|
1981
2061
|
stats &&
|
|
1982
2062
|
(!stats.errors || stats.errors.length === 0) &&
|
|
1983
2063
|
(!stats.warnings || stats.warnings.length === 0) &&
|
|
1984
|
-
stats.
|
|
1985
|
-
stats.assets.every((asset) => !asset.emitted);
|
|
2064
|
+
this.currentHash === stats.hash;
|
|
1986
2065
|
|
|
1987
2066
|
if (shouldEmit) {
|
|
1988
2067
|
this.sendMessage(clients, "still-ok");
|
|
@@ -1990,6 +2069,7 @@ class Server {
|
|
|
1990
2069
|
return;
|
|
1991
2070
|
}
|
|
1992
2071
|
|
|
2072
|
+
this.currentHash = stats.hash;
|
|
1993
2073
|
this.sendMessage(clients, "hash", stats.hash);
|
|
1994
2074
|
|
|
1995
2075
|
if (stats.errors.length > 0 || stats.warnings.length > 0) {
|
|
@@ -2036,7 +2116,6 @@ class Server {
|
|
|
2036
2116
|
};
|
|
2037
2117
|
|
|
2038
2118
|
const chokidar = require("chokidar");
|
|
2039
|
-
|
|
2040
2119
|
const watcher = chokidar.watch(watchPath, finalWatchOptions);
|
|
2041
2120
|
|
|
2042
2121
|
// disabling refreshing on changing the content
|
|
@@ -2129,11 +2208,21 @@ class Server {
|
|
|
2129
2208
|
}
|
|
2130
2209
|
}
|
|
2131
2210
|
|
|
2132
|
-
startCallback(callback) {
|
|
2133
|
-
this.start()
|
|
2211
|
+
startCallback(callback = () => {}) {
|
|
2212
|
+
this.start()
|
|
2213
|
+
.then(() => callback(null), callback)
|
|
2214
|
+
.catch(callback);
|
|
2134
2215
|
}
|
|
2135
2216
|
|
|
2136
2217
|
async stop() {
|
|
2218
|
+
if (this.bonjour) {
|
|
2219
|
+
await new Promise((resolve) => {
|
|
2220
|
+
this.stopBonjour(() => {
|
|
2221
|
+
resolve();
|
|
2222
|
+
});
|
|
2223
|
+
});
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2137
2226
|
this.webSocketProxies = [];
|
|
2138
2227
|
|
|
2139
2228
|
await Promise.all(this.staticWatchers.map((watcher) => watcher.close()));
|
|
@@ -2187,10 +2276,18 @@ class Server {
|
|
|
2187
2276
|
this.middleware = null;
|
|
2188
2277
|
}
|
|
2189
2278
|
}
|
|
2279
|
+
|
|
2280
|
+
// We add listeners to signals when creating a new Server instance
|
|
2281
|
+
// So ensure they are removed to prevent EventEmitter memory leak warnings
|
|
2282
|
+
for (const item of this.listeners) {
|
|
2283
|
+
process.removeListener(item.name, item.listener);
|
|
2284
|
+
}
|
|
2190
2285
|
}
|
|
2191
2286
|
|
|
2192
|
-
stopCallback(callback) {
|
|
2193
|
-
this.stop()
|
|
2287
|
+
stopCallback(callback = () => {}) {
|
|
2288
|
+
this.stop()
|
|
2289
|
+
.then(() => callback(null), callback)
|
|
2290
|
+
.catch(callback);
|
|
2194
2291
|
}
|
|
2195
2292
|
|
|
2196
2293
|
// TODO remove in the next major release
|