1- const boxen = require ( 'boxen' )
1+ const path = require ( 'path' )
2+ const EventEmitter = require ( 'events' )
23const chalk = require ( 'chalk' )
3- const open = require ( 'open' )
4- const exit = require ( 'exit' )
5- const address = require ( 'address' )
4+ const resolveFrom = require ( 'resolve-from' )
65const prettyBytes = require ( 'pretty-bytes' )
76const webpackMerge = require ( 'webpack-merge' )
87const webpack = require ( 'webpack' )
9- const path = require ( 'path' )
10- const WebpackDevServer = require ( 'webpack-dev-server' )
11- const VirtualModulesPlugin = require ( '../webpack/plugins/virtual-modules' )
128const CaseSensitivePathsPlugin = require ( 'case-sensitive-paths-webpack-plugin' )
13- const resolveFrom = require ( 'resolve-from' )
14-
159const createBaseWebpackConfig = require ( '../webpack/create-base-config' )
1610const applyCSSRules = require ( '../webpack/apply-css-rules' )
17- const generateModules = require ( '../webpack/generate-modules' )
18-
19- const DEFAULT_HOST = '0.0.0.0'
20- const DEFAULT_PORT = 9000
2111
2212async function dev ( gatherer = { } , runtime , cliOptions = { } ) {
23- const { api, events } = gatherer
13+ const { api } = gatherer
2414 const nutConfig = await api . getConfig ( )
2515
26- const host = nutConfig . host || DEFAULT_HOST
27- const port = nutConfig . port || DEFAULT_PORT
28-
29- const dynamicPages = [ ]
30- let lockedDynamicPages = [ ]
31-
32- const modules = await generateModules ( await api . getArtifacts ( ) , {
33- env : 'dev' ,
34- cliOptions,
35- dynamicPages,
36- lockedDynamicPages,
37- } )
38-
39- let virtualModules
40-
4116 const webpackConfig = createBaseWebpackConfig ( nutConfig )
4217
4318 webpackConfig . mode ( 'development' )
@@ -52,12 +27,7 @@ async function dev( gatherer = {}, runtime, cliOptions = {} ) {
5227
5328 applyCSSRules ( webpackConfig , 'dev' )
5429
55- webpackConfig . plugin ( 'virtual-modules' )
56- . init ( ( Plugin , args ) => {
57- virtualModules = new Plugin ( ...args )
58- return virtualModules
59- } )
60- . use ( VirtualModulesPlugin , [ modules ] )
30+ const emitter = new EventEmitter ( )
6131
6232 await runtime . apply ( {
6333 env : 'development' ,
@@ -73,7 +43,8 @@ async function dev( gatherer = {}, runtime, cliOptions = {} ) {
7343
7444 return require ( resolved )
7545 }
76- }
46+ } ,
47+ events : emitter ,
7748 } )
7849
7950 if ( typeof nutConfig . chainWebpack === 'function' ) {
@@ -99,270 +70,7 @@ async function dev( gatherer = {}, runtime, cliOptions = {} ) {
9970 console . log ( chalk . gray ( `\n${ prettyBytes ( heapUsed ) } Memory Used\n` ) )
10071 } )
10172
102- const waitCallbacks = [ ]
103- compiler . hooks . done . tap ( 'wait-until-valid' , ( ) => {
104- let callback = waitCallbacks . shift ( )
105- while ( callback ) {
106- callback ( )
107- callback = waitCallbacks . shift ( )
108- }
109- } )
110-
111- function waitUntilValid ( ) {
112- const deferred = { }
113-
114- deferred . promise = new Promise ( ( resolve , reject ) => {
115- deferred . resolve = resolve
116- deferred . reject = reject
117- } )
118-
119- waitCallbacks . push ( deferred . resolve )
120-
121- return deferred . promise
122- }
123-
124- let devServerOptions = {
125- contentBase : './dist' ,
126- host,
127- hot : true ,
128- quiet : true ,
129- headers : {
130- 'Access-Control-Allow-Origin' : '*' ,
131- } ,
132- historyApiFallback : true ,
133- before ( app ) {
134- app . get ( `/_nut_dynamic_build_page` , async ( req , res ) => {
135- const page = req . query . page
136-
137- if ( ! cliOptions . dynamic ) {
138- return res . json ( {
139- success : true ,
140- waitHotApply : false ,
141- } )
142- }
143-
144- // prevent waiting for valid
145- if ( dynamicPages . includes ( page ) ) {
146- return res . json ( {
147- success : true ,
148- waitHotApply : false ,
149- } )
150- }
151-
152- dynamicPages . push ( page )
153-
154- const modules = await generateModules ( await api . getArtifacts ( ) , {
155- env : 'dev' ,
156- cliOptions,
157- dynamicPages,
158- lockedDynamicPages,
159- } )
160-
161- if ( Object . keys ( modules ) . length > 0 ) {
162- for ( const [ path , content ] of Object . entries ( modules ) ) {
163- virtualModules . writeModule (
164- path ,
165- content
166- )
167- }
168-
169- await waitUntilValid ( )
170- }
171-
172- res . json ( {
173- success : true ,
174- waitHotApply : true ,
175- } )
176- } )
177- } ,
178- after ( app ) {
179- // rebuild slim routes(without unused HMR code) before following requests
180- app . use ( async ( req , res , next ) => {
181- if ( ! cliOptions . dynamic ) {
182- return next ( )
183- }
184-
185- if ( req . path === '/index.html' ) {
186- lockedDynamicPages = dynamicPages . slice ( )
187-
188- const modules = await generateModules ( await api . getArtifacts ( ) , {
189- env : 'dev' ,
190- cliOptions,
191- dynamicPages,
192- // used for generate `module.hot.accept`s, ensure no page refresh
193- lockedDynamicPages,
194- } )
195-
196- if ( Object . keys ( modules ) . length > 0 ) {
197- for ( const [ path , content ] of Object . entries ( modules ) ) {
198- virtualModules . writeModule (
199- path ,
200- content
201- )
202- }
203-
204- await waitUntilValid ( )
205- }
206- }
207-
208- next ( )
209- } )
210- } ,
211- }
212-
213- if ( nutConfig . devServer ) {
214- // before
215- const userDevServerBefore = nutConfig . devServer . before
216- const nutDevServerBefore = devServerOptions . before
217-
218- if ( userDevServerBefore ) {
219- devServerOptions . before = function ( ...args ) {
220- userDevServerBefore ( ...args )
221- nutDevServerBefore ( ...args )
222- }
223-
224- delete nutConfig . devServer . before
225- }
226-
227- // after
228- const userDevServerAfter = nutConfig . devServer . after
229- const nutDevServerAfter = devServerOptions . after
230-
231- if ( userDevServerAfter ) {
232- devServerOptions . after = function ( ...args ) {
233- nutDevServerAfter ( ...args )
234- userDevServerAfter ( ...args )
235- }
236-
237- delete nutConfig . devServer . after
238- }
239-
240- devServerOptions = Object . assign ( devServerOptions , nutConfig . devServer )
241- }
242-
243- WebpackDevServer . addDevServerEntrypoints ( finalWebpackConfig , devServerOptions )
244- const server = new WebpackDevServer ( compiler , devServerOptions )
245-
246- server . listen ( port , host , ( ) => {
247- const routerMode = ( nutConfig . router && nutConfig . router . mode ) || 'hash'
248-
249- if ( cliOptions . singlePage ) {
250- console . log (
251- boxen (
252- `Your sinlg page is available at${
253- getTips ( {
254- host,
255- port,
256- routerMode,
257- page : cliOptions . singlePage
258- } )
259- } `,
260- {
261- padding : 1 ,
262- borderColor : 'gray'
263- }
264- )
265- )
266- } else {
267- console . log (
268- boxen (
269- `Your application is running at${ getTips ( { host, port } ) } ` ,
270- {
271- padding : 1 ,
272- borderColor : 'gray'
273- }
274- )
275- )
276- }
277-
278- console . log ( '\n' + chalk . gray ( 'Tips: Press "Enter" to open in browser' ) + '\n' )
279-
280- // modified from:
281- // https://github.com/facebook/jest/blob/b7cb5221bb06b6fe63c1a5e725ddbc1aaa82d306/packages/jest-core/src/watch.ts#L445
282- const stdin = process . stdin
283- const CONTROL_C = '\u0003'
284- const CONTROL_D = '\u0004'
285- const ENTER = '\r'
286-
287- if ( typeof stdin . setRawMode === 'function' ) {
288- stdin . setRawMode ( true )
289- stdin . resume ( )
290- stdin . setEncoding ( 'utf8' )
291- stdin . on ( 'data' , async key => {
292- if ( key === CONTROL_C || key === CONTROL_D ) {
293- if ( typeof stdin . setRawMode === 'function' ) {
294- stdin . setRawMode ( false )
295- }
296- exit ( 0 )
297- return
298- }
299-
300- switch ( key ) {
301- case ENTER :
302- await open ( getOpenUrl ( {
303- host,
304- port,
305- routerMode,
306- page : cliOptions . singlePage
307- } ) )
308- break
309- default :
310- break
311- }
312- } )
313- }
314- } )
315-
316- function getOpenUrl ( { host, port, routerMode = 'hash' , page } ) {
317- const url = 'http://' + host + ':' + port
318-
319- let suffix = ''
320- if ( page ) {
321- suffix = ( routerMode === 'hash' ? '/#/' : '/' ) + page
322- }
323-
324- return url + suffix
325- }
326-
327- function getTips ( { host, port, routerMode, page } ) {
328- const url = 'http://' + host + ':' + port
329- const lanIP = address . ip ( )
330- const lanUrl = lanIP ? `http://${ lanIP } :${ port } ` : ''
331-
332- let suffix = ''
333- if ( page ) {
334- suffix = ( routerMode === 'hash' ? '/#/' : '/' ) + page
335- }
336-
337- const localTips = `\n\nLocal: ${ chalk . cyan ( url + suffix ) } `
338- const lanTips = lanUrl ? `\n\nNetwork: ${ chalk . cyan ( lanUrl + suffix ) } ` : ''
339-
340- return localTips + lanTips
341- }
342-
343- events . on ( 'change' , async ( ) => {
344- if ( ! virtualModules ) {
345- return
346- }
347-
348- try {
349- const modules = await generateModules ( await api . getArtifacts ( ) , {
350- env : 'dev' ,
351- cliOptions,
352- dynamicPages,
353- lockedDynamicPages,
354- } )
355-
356- for ( const [ path , content ] of Object . entries ( modules ) ) {
357- virtualModules . writeModule (
358- path ,
359- content
360- )
361- }
362- } catch ( e ) {
363- console . log ( e )
364- }
365- } )
73+ emitter . emit ( 'compiler' , compiler , finalWebpackConfig )
36674}
36775
36876module . exports = dev
0 commit comments