separate HMR listeners
This commit is contained in:
		
							parent
							
								
									69f902c927
								
							
						
					
					
						commit
						2b83a2abe6
					
				| @ -1,4 +1,6 @@ | ||||
| import { type StateCapture } from "./hmr-react.tsx"; | ||||
| type Processor = (filename:string)=>void; | ||||
| const Processors:Set<Processor> = new Set(); | ||||
| export const Process =(p:Processor)=>Processors.add(p) | ||||
| 
 | ||||
| const FileListeners = new Map() as Map<string, Array<(module:unknown)=>void>>; | ||||
| export const FileListen =(inPath:string, inHandler:()=>void)=> | ||||
| @ -15,56 +17,7 @@ Socket.addEventListener('message', async(event:{data:string})=> | ||||
|     // send the updated members to any listeners for that file
 | ||||
|     const reImport = await import(document.location.origin+event.data+"?reload="+Math.random()); | ||||
|     FileListeners.get(event.data)?.forEach(reExport=>reExport(reImport)); | ||||
|     HMR.update(); | ||||
|     Processors.forEach(p=>p(event.data)) | ||||
| }); | ||||
| Socket.addEventListener("error", ()=>{clearInterval(SocketTimer); console.log("HMR socket lost")}) | ||||
| const SocketTimer = setInterval(()=>{Socket.send("ping")}, 5000); | ||||
| 
 | ||||
| /* | ||||
| 
 | ||||
| Each custom component is secretly modified to have an extra state and id. | ||||
| When there is an HMR update, this state is changed, forcing it to re-render. | ||||
| 
 | ||||
| Each *user-created* React.useState is secretly modified and accompanied by an ID. | ||||
| Every time its state is set, the HMR.statesNew map for this ID is set to contain the new state and updater. | ||||
| When a component is removed, any of it's states in HMR.statesNew are also removed.  | ||||
| (HMR.statesNew is the "running total" of all states currently at play). | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| When a state is interacted with: | ||||
| - statesNew for this id is set | ||||
| - the internal state is also set in the traditional way | ||||
| 
 | ||||
| When there is an HMR update: | ||||
| - All custom components are re-rendered... | ||||
|   for each useState(value) call that then happens in the re-render: | ||||
|   - if there is a "statesOld" value for this state, use that and ignore the passed value, otherwise use the passed value | ||||
|   - if this state has not been interacted with since the last reload (statesNew is empty at this id), set statesNew<id> with whatever is in statesOld<id> | ||||
| - statesNew is moved into *statesOld* | ||||
| - statesNew is cleared. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| const HMR = | ||||
| { | ||||
|     reloads:1, | ||||
|     RegisteredComponents: new Map() as Map<string, ()=>void>, | ||||
|     statesNew: new Map() as Map<string, StateCapture>, | ||||
|     statesOld: new Map() as Map<string, StateCapture>, | ||||
|     wireframe: false, | ||||
|     RegisterComponent(reactID:string, value:()=>void):void | ||||
|     { | ||||
|         this.RegisteredComponents.set(reactID, value); | ||||
|     }, | ||||
|     update() | ||||
|     { | ||||
|         this.reloads++; | ||||
|         this.RegisteredComponents.forEach(handler=>handler()); | ||||
|         this.RegisteredComponents.clear(); | ||||
|         this.statesOld = this.statesNew; | ||||
|         this.statesNew = new Map(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| export {HMR}; | ||||
| const SocketTimer = setInterval(()=>{Socket.send("ping")}, 5000); | ||||
| @ -1,5 +1,56 @@ | ||||
| import * as ReactParts from "react-original"; | ||||
| import { HMR } from "./hmr-listen.tsx"; | ||||
| import { Process } from "./hmr-listen.tsx"; | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
| 
 | ||||
| Each custom component is secretly modified to have an extra state and id. | ||||
| When there is an HMR update, this state is changed, forcing it to re-render. | ||||
| 
 | ||||
| Each *user-created* React.useState is secretly modified and accompanied by an ID. | ||||
| Every time its state is set, the HMR.statesNew map for this ID is set to contain the new state and updater. | ||||
| When a component is removed, any of it's states in HMR.statesNew are also removed.  | ||||
| (HMR.statesNew is the "running total" of all states currently at play). | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| When a state is interacted with: | ||||
| - statesNew for this id is set | ||||
| - the internal state is also set in the traditional way | ||||
| 
 | ||||
| When there is an HMR update: | ||||
| - All custom components are re-rendered... | ||||
|   for each useState(value) call that then happens in the re-render: | ||||
|   - if there is a "statesOld" value for this state, use that and ignore the passed value, otherwise use the passed value | ||||
|   - if this state has not been interacted with since the last reload (statesNew is empty at this id), set statesNew<id> with whatever is in statesOld<id> | ||||
| - statesNew is moved into *statesOld* | ||||
| - statesNew is cleared. | ||||
| 
 | ||||
| */ | ||||
| const HMR = | ||||
| { | ||||
|     reloads:1, | ||||
|     RegisteredComponents: new Map() as Map<string, ()=>void>, | ||||
|     statesNew: new Map() as Map<string, StateCapture>, | ||||
|     statesOld: new Map() as Map<string, StateCapture>, | ||||
|     wireframe: false, | ||||
|     RegisterComponent(reactID:string, value:()=>void):void | ||||
|     { | ||||
|         this.RegisteredComponents.set(reactID, value); | ||||
|     }, | ||||
|     update() | ||||
|     { | ||||
|         this.reloads++; | ||||
|         this.RegisteredComponents.forEach(handler=>handler()); | ||||
|         this.RegisteredComponents.clear(); | ||||
|         this.statesOld = this.statesNew; | ||||
|         this.statesNew = new Map(); | ||||
|     } | ||||
| }; | ||||
| Process(()=>HMR.update()) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| export type StateType = boolean|number|string|Record<string, string> | ||||
| export type StateCapture = {state:StateType, set:ReactParts.StateUpdater<StateType>, reload:number}; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user