@@ -23,10 +23,9 @@ function main() {
2323 const editorMainBundle = new CachedBundle ( 'vs/editor/editor.main' , moduleIdMapper ) ;
2424 fileServer . overrideFileContent ( editorMainBundle . entryModulePath , ( ) => editorMainBundle . bundle ( ) ) ;
2525
26- const hotReloadJsCode = getHotReloadCode ( new URL ( '/file-changes' , server . url ) ) ;
2726 const loaderPath = path . join ( rootDir , 'out/vs/loader.js' ) ;
2827 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 ) ) ) )
3029 ) ;
3130
3231 const watcher = DirWatcher . watchRecursively ( moduleIdMapper . rootDir ) ;
@@ -35,7 +34,7 @@ function main() {
3534 editorMainBundle . bundle ( ) ;
3635 console . log ( `${ new Date ( ) . toLocaleTimeString ( ) } , file change: ${ path } ` ) ;
3736 } ) ;
38- server . use ( '/file-changes' , handleGetFileChangesRequest ( watcher , fileServer ) ) ;
37+ server . use ( '/file-changes' , handleGetFileChangesRequest ( watcher , fileServer , moduleIdMapper ) ) ;
3938
4039 console . log ( `Server listening on ${ server . url } ` ) ;
4140}
@@ -169,6 +168,12 @@ function getContentType(filePath: string): string {
169168 return 'image/png' ;
170169 case '.jpg' :
171170 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' ;
172177 default :
173178 return 'text/plain' ;
174179 }
@@ -215,56 +220,107 @@ class DirWatcher {
215220 }
216221}
217222
218- function handleGetFileChangesRequest ( watcher : DirWatcher , fileServer : FileServer ) : ChainableRequestHandler {
223+ function handleGetFileChangesRequest ( watcher : DirWatcher , fileServer : FileServer , moduleIdMapper : SimpleModuleIdPathMapper ) : ChainableRequestHandler {
219224 return async ( req , res ) => {
220225 res . writeHead ( 200 , { 'Content-Type' : 'text/plain' } ) ;
221226 const d = watcher . onDidChange ( fsPath => {
222227 const path = fileServer . filePathToUrlPath ( fsPath ) ;
223228 if ( path ) {
224- res . write ( JSON . stringify ( { changedPath : path } ) + '\n' ) ;
229+ res . write ( JSON . stringify ( { changedPath : path , moduleId : moduleIdMapper . getModuleId ( fsPath ) } ) + '\n' ) ;
225230 }
226231 } ) ;
227232 res . on ( 'close' , ( ) => d . dispose ( ) ) ;
228233 } ;
229234}
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+ ) ;
230240
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+ }
252303 }
253- } else {
254- $sendMessageToParent({ kind: "reload" });
304+
305+ if ( ! handled ) { reloadFn ( ) ; }
255306 }
256307 }
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+ } ) ;
263312
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 ) } );
266321` ;
267- return additionalJsCode ;
322+
323+ return `${ loaderJsCode } \n${ additionalJsCode } ` ;
268324}
269325
270326// #endregion
0 commit comments