3
3
error,
4
4
hasProjectYarn,
5
5
hasProjectPnpm,
6
- openBrowser,
7
6
IpcMessenger
8
7
} = require ( '@vue/cli-shared-utils' )
9
8
@@ -37,7 +36,6 @@ module.exports = (api, options) => {
37
36
const isInContainer = checkInContainer ( )
38
37
const isProduction = process . env . NODE_ENV === 'production'
39
38
40
- const url = require ( 'url' )
41
39
const { chalk } = require ( '@vue/cli-shared-utils' )
42
40
const webpack = require ( 'webpack' )
43
41
const WebpackDevServer = require ( 'webpack-dev-server' )
@@ -56,20 +54,17 @@ module.exports = (api, options) => {
56
54
. devtool ( 'eval-cheap-module-source-map' )
57
55
}
58
56
59
- webpackConfig
60
- . plugin ( 'hmr' )
61
- . use ( require ( 'webpack/lib/HotModuleReplacementPlugin' ) )
62
-
63
57
// https://github.com/webpack/webpack/issues/6642
64
58
// https://github.com/vuejs/vue-cli/issues/3539
65
59
webpackConfig
66
60
. output
67
61
. globalObject ( `(typeof self !== 'undefined' ? self : this)` )
68
62
69
63
if ( ! process . env . VUE_CLI_TEST && options . devServer . progress !== false ) {
64
+ // the default progress plugin won't show progress due to infrastructreLogging.level
70
65
webpackConfig
71
66
. plugin ( 'progress' )
72
- . use ( webpack . ProgressPlugin )
67
+ . use ( require ( 'progress- webpack-plugin' ) )
73
68
}
74
69
}
75
70
} )
@@ -90,7 +85,7 @@ module.exports = (api, options) => {
90
85
// expose advanced stats
91
86
if ( args . dashboard ) {
92
87
const DashboardPlugin = require ( '../webpack/DashboardPlugin' )
93
- ; ( webpackConfig . plugins = webpackConfig . plugins || [ ] ) . push ( new DashboardPlugin ( {
88
+ webpackConfig . plugins . push ( new DashboardPlugin ( {
94
89
type : 'serve'
95
90
} ) )
96
91
}
@@ -131,38 +126,50 @@ module.exports = (api, options) => {
131
126
)
132
127
133
128
// inject dev & hot-reload middleware entries
129
+ let webSocketURL
134
130
if ( ! isProduction ) {
135
- const sockPath = projectDevServerOptions . sockPath || '/sockjs-node'
136
- const sockjsUrl = publicUrl
131
+ if ( publicHost ) {
137
132
// explicitly configured via devServer.public
138
- ? `?${ publicUrl } &sockPath=${ sockPath } `
139
- : isInContainer
140
- // can't infer public network url if inside a container...
141
- // use client-side inference (note this would break with non-root publicPath)
142
- ? ``
143
- // otherwise infer the url
144
- : `?` + url . format ( {
145
- protocol,
146
- port,
147
- hostname : urls . lanUrlForConfig || 'localhost'
148
- } ) + `&sockPath=${ sockPath } `
149
- const devClients = [
150
- // dev server client
151
- require . resolve ( `webpack-dev-server/client` ) + sockjsUrl ,
152
- // hmr client
153
- require . resolve ( projectDevServerOptions . hotOnly
154
- ? 'webpack/hot/only-dev-server'
155
- : 'webpack/hot/dev-server' )
156
- // TODO custom overlay client
157
- // `@vue/cli-overlay/dist/client`
158
- ]
133
+ webSocketURL = {
134
+ protocol : protocol === 'https' ? 'wss' : 'ws' ,
135
+ hostname : publicHost ,
136
+ port
137
+ }
138
+ } else if ( isInContainer ) {
139
+ // can't infer public network url if inside a container
140
+ // infer it from the browser instead
141
+ webSocketURL = 'auto://0.0.0.0:0/ws'
142
+ } else {
143
+ // otherwise infer the url from the config
144
+ webSocketURL = {
145
+ protocol : protocol === 'https' ? 'wss' : 'ws' ,
146
+ hostname : urls . lanUrlForConfig || 'localhost' ,
147
+ port
148
+ }
149
+ }
150
+
159
151
if ( process . env . APPVEYOR ) {
160
- devClients . push ( `webpack/hot/poll?500` )
152
+ webpackConfig . plugins . push (
153
+ new webpack . EntryPlugin ( __dirname , 'webpack/hot/poll?500' , { name : undefined } )
154
+ )
161
155
}
162
- // inject dev/hot client
163
- addDevClientToEntry ( webpackConfig , devClients )
164
156
}
165
157
158
+ const { projectTargets } = require ( '../util/targets' )
159
+ const supportsIE = ! ! projectTargets
160
+ if ( supportsIE ) {
161
+ webpackConfig . plugins . push (
162
+ // must use undefined as name,
163
+ // to avoid dev server establishing an extra ws connection for the new entry
164
+ new webpack . EntryPlugin ( __dirname , 'whatwg-fetch' , { name : undefined } )
165
+ )
166
+ }
167
+
168
+ // fixme: temporary fix to suppress dev server logging
169
+ // should be more robust to show necessary info but not duplicate errors
170
+ webpackConfig . infrastructureLogging = { ...webpackConfig . infrastructureLogging , level : 'none' }
171
+ webpackConfig . stats = 'errors-only'
172
+
166
173
// create compiler
167
174
const compiler = webpack ( webpackConfig )
168
175
@@ -173,9 +180,7 @@ module.exports = (api, options) => {
173
180
} )
174
181
175
182
// create server
176
- const server = new WebpackDevServer ( compiler , Object . assign ( {
177
- logLevel : 'silent' ,
178
- clientLogLevel : 'silent' ,
183
+ const server = new WebpackDevServer ( Object . assign ( {
179
184
historyApiFallback : {
180
185
disableDotRule : true ,
181
186
htmlAcceptHeaders : [
@@ -184,47 +189,58 @@ module.exports = (api, options) => {
184
189
] ,
185
190
rewrites : genHistoryApiFallbackRewrites ( options . publicPath , options . pages )
186
191
} ,
187
- contentBase : api . resolve ( 'public' ) ,
188
- watchContentBase : ! isProduction ,
189
- hot : ! isProduction ,
190
- injectClient : false ,
191
- compress : isProduction ,
192
- publicPath : options . publicPath ,
193
- overlay : isProduction // TODO disable this
194
- ? false
195
- : { warnings : false , errors : true }
192
+ hot : ! isProduction
196
193
} , projectDevServerOptions , {
194
+ host,
195
+ port,
197
196
https : useHttps ,
198
197
proxy : proxySettings ,
199
- public : publicHost ,
198
+
199
+ static : {
200
+ directory : api . resolve ( 'public' ) ,
201
+ publicPath : options . publicPath ,
202
+ watch : ! isProduction ,
203
+
204
+ ...projectDevServerOptions . static
205
+ } ,
206
+
207
+ client : {
208
+ webSocketURL,
209
+
210
+ logging : 'none' ,
211
+ overlay : isProduction // TODO disable this
212
+ ? false
213
+ : { warnings : false , errors : true } ,
214
+ progress : ! process . env . VUE_CLI_TEST ,
215
+
216
+ ...projectDevServerOptions . client
217
+ } ,
218
+
219
+ open : args . open || projectDevServerOptions . open ,
220
+ setupExitSignals : true ,
221
+
200
222
// eslint-disable-next-line no-shadow
201
- before ( app , server ) {
223
+ onBeforeSetupMiddleware ( server ) {
202
224
// launch editor support.
203
225
// this works with vue-devtools & @vue/cli-overlay
204
- app . use ( '/__open-in-editor' , launchEditorMiddleware ( ( ) => console . log (
226
+ server . app . use ( '/__open-in-editor' , launchEditorMiddleware ( ( ) => console . log (
205
227
`To specify an editor, specify the EDITOR env variable or ` +
206
228
`add "editor" field to your Vue project config.\n`
207
229
) ) )
230
+
208
231
// allow other plugins to register middlewares, e.g. PWA
209
- api . service . devServerConfigFns . forEach ( fn => fn ( app , server ) )
210
- // apply in project middlewares
211
- projectDevServerOptions . before && projectDevServerOptions . before ( app , server )
212
- } ,
213
- // avoid opening browser
214
- open : false
215
- } ) )
232
+ // todo: migrate to the new API interface
233
+ api . service . devServerConfigFns . forEach ( fn => fn ( server . app , server ) )
216
234
217
- ; [ 'SIGINT' , 'SIGTERM' ] . forEach ( signal => {
218
- process . on ( signal , ( ) => {
219
- server . close ( ( ) => {
220
- process . exit ( 0 )
221
- } )
222
- } )
223
- } )
235
+ if ( projectDevServerOptions . onBeforeSetupMiddleware ) {
236
+ projectDevServerOptions . onBeforeSetupMiddleware ( server )
237
+ }
238
+ }
239
+ } ) , compiler )
224
240
225
241
if ( args . stdin ) {
226
242
process . stdin . on ( 'end' , ( ) => {
227
- server . close ( ( ) => {
243
+ server . stopCallback ( ( ) => {
228
244
process . exit ( 0 )
229
245
} )
230
246
} )
@@ -238,7 +254,7 @@ module.exports = (api, options) => {
238
254
process . stdin . on ( 'data' , data => {
239
255
if ( data . toString ( ) === 'close' ) {
240
256
console . log ( 'got close signal!' )
241
- server . close ( ( ) => {
257
+ server . stopCallback ( ( ) => {
242
258
process . exit ( 0 )
243
259
} )
244
260
}
@@ -301,13 +317,6 @@ module.exports = (api, options) => {
301
317
}
302
318
console . log ( )
303
319
304
- if ( args . open || projectDevServerOptions . open ) {
305
- const pageUri = ( projectDevServerOptions . openPage && typeof projectDevServerOptions . openPage === 'string' )
306
- ? projectDevServerOptions . openPage
307
- : ''
308
- openBrowser ( localUrlForBrowser + pageUri )
309
- }
310
-
311
320
// Send final app URL
312
321
if ( args . dashboard ) {
313
322
const ipc = new IpcMessenger ( )
@@ -330,28 +339,11 @@ module.exports = (api, options) => {
330
339
}
331
340
} )
332
341
333
- server . listen ( port , host , err => {
334
- if ( err ) {
335
- reject ( err )
336
- }
337
- } )
342
+ server . start ( ) . catch ( err => reject ( err ) )
338
343
} )
339
344
} )
340
345
}
341
346
342
- function addDevClientToEntry ( config , devClient ) {
343
- const { entry } = config
344
- if ( typeof entry === 'object' && ! Array . isArray ( entry ) ) {
345
- Object . keys ( entry ) . forEach ( ( key ) => {
346
- entry [ key ] = devClient . concat ( entry [ key ] )
347
- } )
348
- } else if ( typeof entry === 'function' ) {
349
- config . entry = entry ( devClient )
350
- } else {
351
- config . entry = devClient . concat ( entry )
352
- }
353
- }
354
-
355
347
// https://stackoverflow.com/a/20012536
356
348
function checkInContainer ( ) {
357
349
if ( 'CODESANDBOX_SSE' in process . env ) {
0 commit comments