@@ -10,11 +10,7 @@ const killable = require('killable');
10
10
const express = require ( 'express' ) ;
11
11
const { validate } = require ( 'schema-utils' ) ;
12
12
const normalizeOptions = require ( './utils/normalizeOptions' ) ;
13
- const colors = require ( './utils/colors' ) ;
14
- const routes = require ( './utils/routes' ) ;
15
- const getSocketServerImplementation = require ( './utils/getSocketServerImplementation' ) ;
16
13
const getCompilerConfigArray = require ( './utils/getCompilerConfigArray' ) ;
17
- const getStatsOption = require ( './utils/getStatsOption' ) ;
18
14
const schema = require ( './options.json' ) ;
19
15
20
16
if ( ! process . env . WEBPACK_SERVE ) {
@@ -49,10 +45,6 @@ class Server {
49
45
initialize ( ) {
50
46
this . applyDevServerPlugin ( ) ;
51
47
52
- this . webSocketServerImplementation = getSocketServerImplementation (
53
- this . options
54
- ) ;
55
-
56
48
if ( this . options . client . progress ) {
57
49
this . setupProgressPlugin ( ) ;
58
50
}
@@ -61,10 +53,8 @@ class Server {
61
53
this . setupApp ( ) ;
62
54
this . setupHostHeaderCheck ( ) ;
63
55
this . setupDevMiddleware ( ) ;
64
-
65
56
// Should be after `webpack-dev-middleware`, otherwise other middlewares might rewrite response
66
- routes ( this ) ;
67
-
57
+ this . setupBuiltInRoutes ( ) ;
68
58
this . setupWatchFiles ( ) ;
69
59
this . setupFeatures ( ) ;
70
60
this . createServer ( ) ;
@@ -262,6 +252,71 @@ class Server {
262
252
) ;
263
253
}
264
254
255
+ setupBuiltInRoutes ( ) {
256
+ const { app, middleware } = this ;
257
+
258
+ app . get ( '/__webpack_dev_server__/sockjs.bundle.js' , ( req , res ) => {
259
+ res . setHeader ( 'Content-Type' , 'application/javascript' ) ;
260
+
261
+ const { createReadStream } = require ( 'graceful-fs' ) ;
262
+ const clientPath = path . join ( __dirname , '..' , 'client' ) ;
263
+
264
+ createReadStream (
265
+ path . join ( clientPath , 'modules/sockjs-client/index.js' )
266
+ ) . pipe ( res ) ;
267
+ } ) ;
268
+
269
+ app . get ( '/webpack-dev-server/invalidate' , ( _req , res ) => {
270
+ this . invalidate ( ) ;
271
+
272
+ res . end ( ) ;
273
+ } ) ;
274
+
275
+ app . get ( '/webpack-dev-server' , ( req , res ) => {
276
+ middleware . waitUntilValid ( ( stats ) => {
277
+ res . setHeader ( 'Content-Type' , 'text/html' ) ;
278
+ res . write (
279
+ '<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body>'
280
+ ) ;
281
+
282
+ const statsForPrint =
283
+ typeof stats . stats !== 'undefined'
284
+ ? stats . toJson ( ) . children
285
+ : [ stats . toJson ( ) ] ;
286
+
287
+ res . write ( `<h1>Assets Report:</h1>` ) ;
288
+
289
+ statsForPrint . forEach ( ( item , index ) => {
290
+ res . write ( '<div>' ) ;
291
+
292
+ const name =
293
+ item . name || ( stats . stats ? `unnamed[${ index } ]` : 'unnamed' ) ;
294
+
295
+ res . write ( `<h2>Compilation: ${ name } </h2>` ) ;
296
+ res . write ( '<ul>' ) ;
297
+
298
+ const publicPath = item . publicPath === 'auto' ? '' : item . publicPath ;
299
+
300
+ for ( const asset of item . assets ) {
301
+ const assetName = asset . name ;
302
+ const assetURL = `${ publicPath } ${ assetName } ` ;
303
+
304
+ res . write (
305
+ `<li>
306
+ <strong><a href="${ assetURL } " target="_blank">${ assetName } </a></strong>
307
+ </li>`
308
+ ) ;
309
+ }
310
+
311
+ res . write ( '</ul>' ) ;
312
+ res . write ( '</div>' ) ;
313
+ } ) ;
314
+
315
+ res . end ( '</body></html>' ) ;
316
+ } ) ;
317
+ } ) ;
318
+ }
319
+
265
320
setupCompressFeature ( ) {
266
321
const compress = require ( 'compression' ) ;
267
322
@@ -574,7 +629,47 @@ class Server {
574
629
} ) ;
575
630
}
576
631
632
+ getWebSocketServerImplementation ( ) {
633
+ let implementation ;
634
+ let implementationFound = true ;
635
+
636
+ switch ( typeof this . options . webSocketServer . type ) {
637
+ case 'string' :
638
+ // Could be 'sockjs', in the future 'ws', or a path that should be required
639
+ if ( this . options . webSocketServer . type === 'sockjs' ) {
640
+ implementation = require ( './servers/SockJSServer' ) ;
641
+ } else if ( this . options . webSocketServer . type === 'ws' ) {
642
+ implementation = require ( './servers/WebsocketServer' ) ;
643
+ } else {
644
+ try {
645
+ // eslint-disable-next-line import/no-dynamic-require
646
+ implementation = require ( this . options . webSocketServer . type ) ;
647
+ } catch ( error ) {
648
+ implementationFound = false ;
649
+ }
650
+ }
651
+ break ;
652
+ case 'function' :
653
+ implementation = this . options . webSocketServer . type ;
654
+ break ;
655
+ default :
656
+ implementationFound = false ;
657
+ }
658
+
659
+ if ( ! implementationFound ) {
660
+ throw new Error (
661
+ "webSocketServer (webSocketServer.type) must be a string denoting a default implementation (e.g. 'ws', 'sockjs'), a full path to " +
662
+ 'a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer.js) ' +
663
+ 'via require.resolve(...), or the class itself which extends BaseServer'
664
+ ) ;
665
+ }
666
+
667
+ return implementation ;
668
+ }
669
+
577
670
createWebSocketServer ( ) {
671
+ this . webSocketServerImplementation =
672
+ this . getWebSocketServerImplementation ( ) ;
578
673
// eslint-disable-next-line new-cap
579
674
this . webSocketServer = new this . webSocketServerImplementation ( this ) ;
580
675
@@ -697,7 +792,7 @@ class Server {
697
792
698
793
logStatus ( ) {
699
794
const getColorsOption = ( configArray ) => {
700
- const statsOption = getStatsOption ( configArray ) ;
795
+ const statsOption = this . getStatsOption ( configArray ) ;
701
796
702
797
let colorsEnabled = false ;
703
798
@@ -708,6 +803,25 @@ class Server {
708
803
return colorsEnabled ;
709
804
} ;
710
805
806
+ // TODO change it on https://www.npmjs.com/package/colorette
807
+ const colors = {
808
+ info ( useColor , msg ) {
809
+ if ( useColor ) {
810
+ // Make text blue and bold, so it *pops*
811
+ return `\u001b[1m\u001b[34m${ msg } \u001b[39m\u001b[22m` ;
812
+ }
813
+
814
+ return msg ;
815
+ } ,
816
+ error ( useColor , msg ) {
817
+ if ( useColor ) {
818
+ // Make text red and bold, so it *pops*
819
+ return `\u001b[1m\u001b[31m${ msg } \u001b[39m\u001b[22m` ;
820
+ }
821
+
822
+ return msg ;
823
+ } ,
824
+ } ;
711
825
const useColor = getColorsOption ( getCompilerConfigArray ( this . compiler ) ) ;
712
826
713
827
if ( this . options . ipc ) {
@@ -979,11 +1093,28 @@ class Server {
979
1093
}
980
1094
}
981
1095
1096
+ // eslint-disable-next-line class-methods-use-this
1097
+ getStatsOption ( configArray ) {
1098
+ const isEmptyObject = ( val ) =>
1099
+ typeof val === 'object' && Object . keys ( val ) . length === 0 ;
1100
+
1101
+ // in webpack@4 stats will not be defined if not provided,
1102
+ // but in webpack@5 it will be an empty object
1103
+ const statsConfig = configArray . find (
1104
+ ( configuration ) =>
1105
+ typeof configuration === 'object' &&
1106
+ configuration . stats &&
1107
+ ! isEmptyObject ( configuration . stats )
1108
+ ) ;
1109
+
1110
+ return statsConfig ? statsConfig . stats : { } ;
1111
+ }
1112
+
982
1113
getStats ( statsObj ) {
983
1114
const stats = Server . DEFAULT_STATS ;
984
1115
985
- const configArr = getCompilerConfigArray ( this . compiler ) ;
986
- const statsOption = getStatsOption ( configArr ) ;
1116
+ const configArray = getCompilerConfigArray ( this . compiler ) ;
1117
+ const statsOption = this . getStatsOption ( configArray ) ;
987
1118
988
1119
if ( typeof statsOption === 'object' && statsOption . warningsFilter ) {
989
1120
stats . warningsFilter = statsOption . warningsFilter ;
0 commit comments