@@ -23,10 +23,9 @@ function main() {
23
23
const editorMainBundle = new CachedBundle ( 'vs/editor/editor.main' , moduleIdMapper ) ;
24
24
fileServer . overrideFileContent ( editorMainBundle . entryModulePath , ( ) => editorMainBundle . bundle ( ) ) ;
25
25
26
- const hotReloadJsCode = getHotReloadCode ( new URL ( '/file-changes' , server . url ) ) ;
27
26
const loaderPath = path . join ( rootDir , 'out/vs/loader.js' ) ;
28
27
fileServer . overrideFileContent ( loaderPath , async ( ) =>
29
- Buffer . from ( new TextEncoder ( ) . encode ( ` ${ await fsPromise . readFile ( loaderPath , 'utf8' ) } \n ${ hotReloadJsCode } ` ) )
28
+ Buffer . from ( new TextEncoder ( ) . encode ( makeLoaderJsHotReloadable ( await fsPromise . readFile ( loaderPath , 'utf8' ) , new URL ( '/file-changes' , server . url ) ) ) )
30
29
) ;
31
30
32
31
const watcher = DirWatcher . watchRecursively ( moduleIdMapper . rootDir ) ;
@@ -35,7 +34,7 @@ function main() {
35
34
editorMainBundle . bundle ( ) ;
36
35
console . log ( `${ new Date ( ) . toLocaleTimeString ( ) } , file change: ${ path } ` ) ;
37
36
} ) ;
38
- server . use ( '/file-changes' , handleGetFileChangesRequest ( watcher , fileServer ) ) ;
37
+ server . use ( '/file-changes' , handleGetFileChangesRequest ( watcher , fileServer , moduleIdMapper ) ) ;
39
38
40
39
console . log ( `Server listening on ${ server . url } ` ) ;
41
40
}
@@ -169,6 +168,12 @@ function getContentType(filePath: string): string {
169
168
return 'image/png' ;
170
169
case '.jpg' :
171
170
return 'image/jpg' ;
171
+ case '.svg' :
172
+ return 'image/svg+xml' ;
173
+ case '.html' :
174
+ return 'text/html' ;
175
+ case '.wasm' :
176
+ return 'application/wasm' ;
172
177
default :
173
178
return 'text/plain' ;
174
179
}
@@ -215,56 +220,107 @@ class DirWatcher {
215
220
}
216
221
}
217
222
218
- function handleGetFileChangesRequest ( watcher : DirWatcher , fileServer : FileServer ) : ChainableRequestHandler {
223
+ function handleGetFileChangesRequest ( watcher : DirWatcher , fileServer : FileServer , moduleIdMapper : SimpleModuleIdPathMapper ) : ChainableRequestHandler {
219
224
return async ( req , res ) => {
220
225
res . writeHead ( 200 , { 'Content-Type' : 'text/plain' } ) ;
221
226
const d = watcher . onDidChange ( fsPath => {
222
227
const path = fileServer . filePathToUrlPath ( fsPath ) ;
223
228
if ( path ) {
224
- res . write ( JSON . stringify ( { changedPath : path } ) + '\n' ) ;
229
+ res . write ( JSON . stringify ( { changedPath : path , moduleId : moduleIdMapper . getModuleId ( fsPath ) } ) + '\n' ) ;
225
230
}
226
231
} ) ;
227
232
res . on ( 'close' , ( ) => d . dispose ( ) ) ;
228
233
} ;
229
234
}
235
+ function makeLoaderJsHotReloadable ( loaderJsCode : string , fileChangesUrl : URL ) : string {
236
+ loaderJsCode = loaderJsCode . replace (
237
+ / c o n s t r u c t o r \( e n v , s c r i p t L o a d e r , d e f i n e F u n c , r e q u i r e F u n c , l o a d e r A v a i l a b l e T i m e s t a m p = 0 \) { / ,
238
+ '$&globalThis.$$globalModuleManager = this;'
239
+ ) ;
230
240
231
- function getHotReloadCode ( fileChangesUrl : URL ) : string {
232
- const additionalJsCode = `
233
- function $watchChanges() {
234
- console.log("Connecting to server to watch for changes...");
235
- fetch(${ JSON . stringify ( fileChangesUrl ) } )
236
- .then(async request => {
237
- const reader = request.body.getReader();
238
- let buffer = '';
239
- while (true) {
240
- const { done, value } = await reader.read();
241
- if (done) { break; }
242
- buffer += new TextDecoder().decode(value);
243
- const lines = buffer.split('\\n');
244
- buffer = lines.pop();
245
- for (const line of lines) {
246
- const data = JSON.parse(line);
247
- if (data.changedPath.endsWith('.css')) {
248
- console.log('css changed', data.changedPath);
249
- const styleSheet = [...document.querySelectorAll("link[rel='stylesheet']")].find(l => new URL(l.href, document.location.href).pathname.endsWith(data.changedPath));
250
- if (styleSheet) {
251
- styleSheet.href = styleSheet.href.replace(/\\?.*/, '') + '?' + Date.now();
241
+ const $$globalModuleManager : any = undefined ;
242
+
243
+ // This code will be appended to loader.js
244
+ function $watchChanges ( fileChangesUrl : string ) {
245
+ let reloadFn ;
246
+ if ( globalThis . $sendMessageToParent ) {
247
+ reloadFn = ( ) => globalThis . $sendMessageToParent ( { kind : 'reload' } ) ;
248
+ } else if ( typeof window !== 'undefined' ) {
249
+ reloadFn = ( ) => window . location . reload ( ) ;
250
+ } else {
251
+ reloadFn = ( ) => { } ;
252
+ }
253
+
254
+ console . log ( 'Connecting to server to watch for changes...' ) ;
255
+ ( fetch as any ) ( fileChangesUrl )
256
+ . then ( async request => {
257
+ const reader = request . body . getReader ( ) ;
258
+ let buffer = '' ;
259
+ while ( true ) {
260
+ const { done, value } = await reader . read ( ) ;
261
+ if ( done ) { break ; }
262
+ buffer += new TextDecoder ( ) . decode ( value ) ;
263
+ const lines = buffer . split ( '\n' ) ;
264
+ buffer = lines . pop ( ) ! ;
265
+ for ( const line of lines ) {
266
+ const data = JSON . parse ( line ) ;
267
+ let handled = false ;
268
+ if ( data . changedPath . endsWith ( '.css' ) ) {
269
+ console . log ( 'css changed' , data . changedPath ) ;
270
+ const styleSheet = [ ...document . querySelectorAll ( `link[rel='stylesheet']` ) ] . find ( ( l : any ) => new URL ( l . href , document . location . href ) . pathname . endsWith ( data . changedPath ) ) as any ;
271
+ if ( styleSheet ) {
272
+ styleSheet . href = styleSheet . href . replace ( / \? .* / , '' ) + '?' + Date . now ( ) ;
273
+ }
274
+ handled = true ;
275
+ } else if ( data . changedPath . endsWith ( '.js' ) && data . moduleId ) {
276
+ console . log ( 'js changed' , data . changedPath ) ;
277
+ const moduleId = $$globalModuleManager . _moduleIdProvider . getModuleId ( data . moduleId ) ;
278
+ if ( $$globalModuleManager . _modules2 [ moduleId ] ) {
279
+ const srcUrl = $$globalModuleManager . _config . moduleIdToPaths ( data . moduleId ) ;
280
+ const newSrc = await ( await fetch ( srcUrl ) ) . text ( ) ;
281
+ ( new Function ( 'define' , newSrc ) ) ( function ( deps , callback ) {
282
+ const oldModule = $$globalModuleManager . _modules2 [ moduleId ] ;
283
+ delete $$globalModuleManager . _modules2 [ moduleId ] ;
284
+
285
+ $$globalModuleManager . defineModule ( data . moduleId , deps , callback ) ;
286
+ const newModule = $$globalModuleManager . _modules2 [ moduleId ] ;
287
+ const oldExports = { ...oldModule . exports } ;
288
+
289
+ Object . assign ( oldModule . exports , newModule . exports ) ;
290
+ newModule . exports = oldModule . exports ;
291
+
292
+ handled = true ;
293
+
294
+ for ( const cb of [ ...globalThis . $hotReload_deprecateExports ] ) {
295
+ cb ( oldExports , newModule . exports ) ;
296
+ }
297
+
298
+ if ( handled ) {
299
+ console . log ( 'hot reloaded' , data . moduleId ) ;
300
+ }
301
+ } ) ;
302
+ }
252
303
}
253
- } else {
254
- $sendMessageToParent({ kind: "reload" });
304
+
305
+ if ( ! handled ) { reloadFn ( ) ; }
255
306
}
256
307
}
257
- }
258
- })
259
- .catch(err => {
260
- console.error(err);
261
- setTimeout($watchChanges, 1000);
262
- });
308
+ } ) . catch ( err => {
309
+ console . error ( err ) ;
310
+ setTimeout ( ( ) => $watchChanges ( fileChangesUrl ) , 1000 ) ;
311
+ } ) ;
263
312
264
- }
265
- $watchChanges();
313
+ }
314
+
315
+ const additionalJsCode = `
316
+ (${ ( function ( ) {
317
+ globalThis . $hotReload_deprecateExports = new Set < ( oldExports : any , newExports : any ) => void > ( ) ;
318
+ } ) . toString ( ) } )();
319
+ ${ $watchChanges . toString ( ) }
320
+ $watchChanges(${ JSON . stringify ( fileChangesUrl ) } );
266
321
` ;
267
- return additionalJsCode ;
322
+
323
+ return `${ loaderJsCode } \n${ additionalJsCode } ` ;
268
324
}
269
325
270
326
// #endregion
0 commit comments