@@ -30,7 +30,15 @@ wss.on('connection', (ws) => {
30
30
// In-memory state
31
31
let updateHistory = [ ] ;
32
32
let availableUpdates = [ ] ;
33
- let lastUpdateId = 0 ;
33
+ let clientUpdateTracking = new Map ( ) ; // Track which updates each client has received
34
+
35
+ // Generate a unique webpack-style hash
36
+ function generateWebpackHash ( ) {
37
+ return (
38
+ Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 ) +
39
+ Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 )
40
+ ) ;
41
+ }
34
42
35
43
// Load available updates from updates directory
36
44
function loadAvailableUpdates ( ) {
@@ -67,44 +75,59 @@ function extractDescription(content) {
67
75
// Get pending updates for client
68
76
app . get ( '/api/updates' , ( req , res ) => {
69
77
const clientId = req . query . clientId || 'default' ;
70
- const lastAppliedId = parseInt ( req . query . lastAppliedId ) || 0 ;
71
-
72
- const pendingUpdatesRaw = updateHistory . filter (
73
- ( update ) => update . id > lastAppliedId && update . triggered ,
74
- ) ;
78
+ const currentHash = req . query . currentHash || '0' ;
75
79
76
- const formattedUpdates = pendingUpdatesRaw . map ( ( update ) => {
77
- // Extract module path from content - this is a simplified example
78
- // A more robust solution would parse the JS content or have this info stored
79
- // const modulePathMatch = update.content.match(
80
- // /\*!\*\*\* (\.\/src\/[^\s]+) \*\*\*!/,
81
- // );
82
- // const modulePath = modulePathMatch ? modulePathMatch[1] : update.filename; // Fallback to filename
83
-
84
- return {
80
+ // Get the list of updates this client has already received
81
+ if ( ! clientUpdateTracking . has ( clientId ) ) {
82
+ clientUpdateTracking . set ( clientId , new Set ( ) ) ;
83
+ }
84
+ const clientReceivedUpdates = clientUpdateTracking . get ( clientId ) ;
85
+
86
+ // Find the latest triggered update that:
87
+ // 1. Has a different hash than client's current hash
88
+ // 2. Has not been sent to this client before
89
+ const latestUpdate = updateHistory
90
+ . filter ( ( update ) => {
91
+ return (
92
+ update . triggered &&
93
+ update . webpackHash !== currentHash &&
94
+ ! clientReceivedUpdates . has ( update . updateId )
95
+ ) ;
96
+ } )
97
+ . slice ( - 1 ) [ 0 ] ; // Get the most recent one
98
+
99
+ let formattedUpdate = null ;
100
+ if ( latestUpdate ) {
101
+ // Mark this update as sent to this client
102
+ clientReceivedUpdates . add ( latestUpdate . updateId ) ;
103
+
104
+ formattedUpdate = {
85
105
manifest : {
86
106
c : [ 'index' ] , // Assuming 'index' is the main chunk for all these updates
87
107
r : [ ] , // Removed chunks, empty for now
88
108
m : [
89
109
// modulePath
90
110
] , // Modules affected by this update
91
111
} ,
92
- script : update . content ,
112
+ script : latestUpdate . content ,
93
113
// Keep original update info for reference if needed by client
94
- originalUpdateInfo : {
95
- id : update . id ,
96
- updateId : update . updateId ,
97
- filename : update . filename ,
98
- description : update . description ,
99
- triggered : update . triggered ,
100
- timestamp : update . timestamp ,
114
+ originalInfo : {
115
+ updateId : latestUpdate . updateId ,
116
+ filename : latestUpdate . filename ,
117
+ description : latestUpdate . description ,
118
+ triggered : latestUpdate . triggered ,
119
+ timestamp : latestUpdate . timestamp ,
120
+ webpackHash : latestUpdate . webpackHash ,
101
121
} ,
102
122
} ;
103
- } ) ;
123
+
124
+ console . log (
125
+ `Sending update ${ latestUpdate . updateId } to client ${ clientId } with hash ${ latestUpdate . webpackHash } ` ,
126
+ ) ;
127
+ }
104
128
105
129
res . json ( {
106
- updates : formattedUpdates ,
107
- lastUpdateId : Math . max ( ...updateHistory . map ( ( u ) => u . id ) , 0 ) ,
130
+ update : formattedUpdate , // Single update object instead of array
108
131
serverTime : Date . now ( ) ,
109
132
} ) ;
110
133
} ) ;
@@ -126,14 +149,17 @@ app.post('/api/trigger-update', (req, res) => {
126
149
return res . status ( 404 ) . json ( { error : 'Update not found' } ) ;
127
150
}
128
151
152
+ // Generate a unique webpack hash for this update
153
+ const webpackHash = generateWebpackHash ( ) ;
154
+
129
155
const triggeredUpdate = {
130
- id : ++ lastUpdateId ,
131
156
updateId : updateId ,
132
157
filename : update . filename ,
133
158
description : description || update . description ,
134
159
content : update . content ,
135
160
triggered : true ,
136
161
timestamp : Date . now ( ) ,
162
+ webpackHash : webpackHash ,
137
163
} ;
138
164
139
165
updateHistory . push ( triggeredUpdate ) ;
@@ -159,19 +185,45 @@ app.post('/api/trigger-basic-debugger-test', (req, res) => {
159
185
const { description = 'Basic Debugger Test Update' } = req . body ;
160
186
161
187
// Create a test update specifically for basic debugger
188
+ // Generate a unique hash for this update to prevent continuous reloads
189
+ const uniqueUpdateHash = `basic-debugger-test-${ Date . now ( ) . toString ( 36 ) } ` ;
190
+
191
+ // Generate a unique webpack hash for this update
192
+ const webpackHash = generateWebpackHash ( ) ;
193
+
162
194
const testUpdate = {
163
- id : ++ lastUpdateId ,
164
- updateId : 'basic-debugger-test' ,
165
- filename : 'basic-debugger-test.hot-update.js' ,
195
+ updateId : uniqueUpdateHash , // Use unique hash instead of fixed string
196
+ filename : `${ uniqueUpdateHash } .hot-update.js` ,
166
197
description : description ,
198
+ webpackHash : webpackHash ,
167
199
content : `/** Basic Debugger Test Update */
168
200
exports.id = 'main';
169
- exports.ids = ['something'];
170
- exports.modules = {};
201
+ exports.ids = null;
202
+ exports.modules = {
203
+ './src/index.js': function(module, exports, __webpack_require__) {
204
+ console.log('🧪 Basic debugger test module loaded at:', new Date().toISOString());
205
+ console.log('🔄 This is a test hot update for the basic debugger');
206
+
207
+ // Test module that demonstrates HMR functionality
208
+ const testData = {
209
+ timestamp: Date.now(),
210
+ message: 'Hot update applied successfully!',
211
+ counter: Math.floor(Math.random() * 1000)
212
+ };
213
+
214
+ console.log('📊 Test data:', testData);
215
+ if (module.hot) {
216
+ console.log('🔥 Debug demo has module.hot support');
217
+ // process.exit();
218
+ module.hot.accept();
219
+ }
220
+ module.exports = testData;
221
+ }
222
+ };
171
223
exports.runtime = /******/ function (__webpack_require__) {
172
224
/******/ /* webpack/runtime/getFullHash */
173
225
/******/ (() => {
174
- /******/ __webpack_require__.h = () => 'basic-debugger-test ';
226
+ /******/ __webpack_require__.h = () => '${ webpackHash } ';
175
227
/******/
176
228
})();
177
229
/******/
@@ -204,7 +256,7 @@ app.get('/api/status', (req, res) => {
204
256
connectedClients : connectedClients . size ,
205
257
availableUpdates : availableUpdates . length ,
206
258
updateHistory : updateHistory . length ,
207
- lastUpdateId : lastUpdateId ,
259
+ totalUpdates : updateHistory . length ,
208
260
uptime : process . uptime ( ) ,
209
261
} ) ;
210
262
} ) ;
0 commit comments