1
1
'use strict' ;
2
2
3
- const ipaddr = require ( 'ipaddr.js' ) ;
4
- const getSocketClientPath = require ( './getSocketClientPath' ) ;
5
-
6
3
/**
7
4
* An Entry, it can be of type string or string[] or Object<string | string[],string>
8
5
* @typedef {(string[] | string | Object<string | string[],string>) } Entry
@@ -16,11 +13,66 @@ class DevServerPlugin {
16
13
this . options = options ;
17
14
}
18
15
16
+ getWebsocketTransport ( ) {
17
+ let ClientImplementation ;
18
+ let clientImplementationFound = true ;
19
+
20
+ const isKnownWebSocketServerImplementation =
21
+ typeof this . options . webSocketServer . type === 'string' &&
22
+ ( this . options . webSocketServer . type === 'ws' ||
23
+ this . options . webSocketServer . type === 'sockjs' ) ;
24
+
25
+ let clientTransport ;
26
+
27
+ if ( typeof this . options . client . transport !== 'undefined' ) {
28
+ clientTransport = this . options . client . transport ;
29
+ } else if ( isKnownWebSocketServerImplementation ) {
30
+ clientTransport = this . options . webSocketServer . type ;
31
+ }
32
+
33
+ switch ( typeof clientTransport ) {
34
+ case 'string' :
35
+ // could be 'sockjs', 'ws', or a path that should be required
36
+ if ( clientTransport === 'sockjs' ) {
37
+ ClientImplementation = require . resolve (
38
+ '../../client/clients/SockJSClient'
39
+ ) ;
40
+ } else if ( clientTransport === 'ws' ) {
41
+ ClientImplementation = require . resolve (
42
+ '../../client/clients/WebsocketClient'
43
+ ) ;
44
+ } else {
45
+ try {
46
+ // eslint-disable-next-line import/no-dynamic-require
47
+ ClientImplementation = require . resolve ( clientTransport ) ;
48
+ } catch ( e ) {
49
+ clientImplementationFound = false ;
50
+ }
51
+ }
52
+ break ;
53
+ default :
54
+ clientImplementationFound = false ;
55
+ }
56
+
57
+ if ( ! clientImplementationFound ) {
58
+ throw new Error (
59
+ `${
60
+ ! isKnownWebSocketServerImplementation
61
+ ? 'When you use custom web socket implementation you must explicitly specify client.transport. '
62
+ : ''
63
+ } client.transport must be a string denoting a default implementation (e.g. 'sockjs', 'ws') or a full path to a JS file via require.resolve(...) which exports a class `
64
+ ) ;
65
+ }
66
+
67
+ return ClientImplementation ;
68
+ }
69
+
19
70
/**
20
71
* @returns {string }
21
72
*/
22
73
getWebSocketURL ( ) {
23
74
const { options } = this ;
75
+ const searchParams = new URLSearchParams ( ) ;
24
76
25
77
/** @type {"ws:" | "wss:" | "http:" | "https:" | "auto:" } */
26
78
let protocol ;
@@ -32,6 +84,16 @@ class DevServerPlugin {
32
84
protocol = options . https ? 'wss:' : 'ws:' ;
33
85
}
34
86
87
+ searchParams . set ( 'protocol' , protocol ) ;
88
+
89
+ if ( typeof options . client . webSocketURL . username !== 'undefined' ) {
90
+ searchParams . set ( 'username' , options . client . webSocketURL . username ) ;
91
+ }
92
+
93
+ if ( typeof options . client . webSocketURL . password !== 'undefined' ) {
94
+ searchParams . set ( 'password' , options . client . webSocketURL . password ) ;
95
+ }
96
+
35
97
/** @type {string } */
36
98
let hostname ;
37
99
@@ -59,6 +121,8 @@ class DevServerPlugin {
59
121
hostname = '0.0.0.0' ;
60
122
}
61
123
124
+ searchParams . set ( 'hostname' , hostname ) ;
125
+
62
126
/** @type {number | string } */
63
127
let port ;
64
128
@@ -83,17 +147,18 @@ class DevServerPlugin {
83
147
}
84
148
// The `port` option is not specified or set to `auto`
85
149
else {
86
- port = 0 ;
150
+ port = '0' ;
87
151
}
88
152
153
+ searchParams . set ( 'port' , String ( port ) ) ;
154
+
89
155
/** @type {string } */
90
156
let pathname = '' ;
91
157
92
158
// We are proxying dev server and need to specify custom `pathname`
93
159
if ( typeof options . client . webSocketURL . pathname !== 'undefined' ) {
94
160
pathname = options . client . webSocketURL . pathname ;
95
161
}
96
-
97
162
// Web socket server works on custom `path`
98
163
else if (
99
164
typeof options . webSocketServer . options . prefix !== 'undefined' ||
@@ -104,42 +169,13 @@ class DevServerPlugin {
104
169
options . webSocketServer . options . path ;
105
170
}
106
171
107
- /** @type {string } */
108
- let username = '' ;
109
-
110
- if ( typeof options . client . webSocketURL . username !== 'undefined' ) {
111
- username = options . client . webSocketURL . username ;
112
- }
113
-
114
- /** @type {string } */
115
- let password = '' ;
116
-
117
- if ( typeof options . client . webSocketURL . password !== 'undefined' ) {
118
- password = options . client . webSocketURL . password ;
119
- }
120
-
121
- const searchParams = new URLSearchParams ( ) ;
172
+ searchParams . set ( 'pathname' , pathname ) ;
122
173
123
174
if ( typeof options . client . logging !== 'undefined' ) {
124
175
searchParams . set ( 'logging' , options . client . logging ) ;
125
176
}
126
177
127
- const searchParamsString = searchParams . toString ( ) ;
128
-
129
- return encodeURIComponent (
130
- new URL (
131
- `${ protocol } //${ username } ${ password ? `:${ password } ` : '' } ${
132
- username || password ? `@` : ''
133
- } ${ ipaddr . IPv6 . isIPv6 ( hostname ) ? `[${ hostname } ]` : hostname } ${
134
- port ? `:${ port } ` : ''
135
- } ${ pathname || '/' } ${
136
- searchParamsString ? `?${ searchParamsString } ` : ''
137
- } `
138
- ) . toString ( )
139
- ) . replace (
140
- / [ ! ' ( ) * ] / g,
141
- ( character ) => `%${ character . charCodeAt ( 0 ) . toString ( 16 ) } `
142
- ) ;
178
+ return searchParams . toString ( ) ;
143
179
}
144
180
145
181
/**
@@ -315,7 +351,7 @@ class DevServerPlugin {
315
351
}
316
352
317
353
const providePlugin = new webpack . ProvidePlugin ( {
318
- __webpack_dev_server_client__ : getSocketClientPath ( this . options ) ,
354
+ __webpack_dev_server_client__ : this . getWebsocketTransport ( ) ,
319
355
} ) ;
320
356
321
357
providePlugin . apply ( compiler ) ;
0 commit comments