miolo-react 3.0.0-beta.216 → 3.0.0-beta.219

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miolo-react",
3
- "version": "3.0.0-beta.216",
3
+ "version": "3.0.0-beta.219",
4
4
  "description": "React utils for miolo",
5
5
  "author": "Donato Lorenzo <donato@afialapis.com>",
6
6
  "contributors": [
@@ -30,7 +30,7 @@
30
30
  "prepublishOnly": "npm run lint"
31
31
  },
32
32
  "dependencies": {
33
- "idb-keyval": "^6.2.5",
33
+ "idb-keyval": "^6.2.6",
34
34
  "miolo-cli": "../miolo-cli"
35
35
  },
36
36
  "peerDependencies": {
@@ -1,11 +1,11 @@
1
1
  import { miolo_client } from "miolo-cli"
2
- import { useCallback, useEffect, useState } from "react"
2
+ import { useCallback, /*useEffect,*/ useState } from "react"
3
3
  import { useSsrDataOrReload } from "../ssr/useSsrDataOrReload.mjs"
4
4
  import Context from "./MioloContext.mjs"
5
5
 
6
6
  const MioloContextProvider = ({ context, children }) => {
7
7
  const [innerContext, setInnerContext] = useState(context)
8
- const [mioloObj, setMioloObj] = useState(miolo_client(context))
8
+ const [mioloObj, _setMioloObj] = useState(miolo_client(context))
9
9
 
10
10
  /*useEffect(() => {
11
11
  setInnerContext(context)
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useMemo, useState } from "react"
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react"
2
2
  import getSsrDataFromContext from "./getSsrDataFromContext.mjs"
3
3
  import useOnWindowFocus from "./useOnWindowFocus.mjs"
4
4
  import usePropsCheck from "./usePropsCheck.mjs"
@@ -11,6 +11,38 @@ const _makeSerializable = (obj) => {
11
11
  }
12
12
  }
13
13
 
14
+ let _historyPatched = false
15
+ const patchHistory = () => {
16
+ if (typeof window === "undefined" || _historyPatched) return
17
+
18
+ const originalPushState = window.history.pushState
19
+ window.history.pushState = function (...args) {
20
+ const ret = originalPushState.apply(this, args)
21
+ window.dispatchEvent(new Event("miolo-navigation"))
22
+ return ret
23
+ }
24
+
25
+ const originalReplaceState = window.history.replaceState
26
+ window.history.replaceState = function (...args) {
27
+ const ret = originalReplaceState.apply(this, args)
28
+ window.dispatchEvent(new Event("miolo-navigation"))
29
+ return ret
30
+ }
31
+
32
+ window.addEventListener("popstate", () => {
33
+ window.dispatchEvent(new Event("miolo-navigation"))
34
+ })
35
+
36
+ _historyPatched = true
37
+ }
38
+
39
+ const globalSocketState = {
40
+ rooms: new Map(),
41
+ unsubscribeTimers: new Map(),
42
+ lastSubscribeEmitted: new Map(),
43
+ versionsRequestedAt: 0
44
+ }
45
+
14
46
  const useSsrDataOrReload = (context, miolo, name, options) => {
15
47
  const { fetcher, socket, logger } = miolo
16
48
  const {
@@ -51,6 +83,7 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
51
83
  )
52
84
  const [status, setStatus] = useState(ssrDataFromContext !== undefined ? "loaded" : "idle")
53
85
  const [error, setError] = useState(undefined)
86
+ const pendingLazyRefreshRef = useRef(false)
54
87
 
55
88
  const cacheInvalidate = useCallback(async () => {
56
89
  if (typeof window !== "undefined") {
@@ -95,6 +128,7 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
95
128
 
96
129
  const updateSsrData = useCallback(
97
130
  (data) => {
131
+ pendingLazyRefreshRef.current = false
98
132
  setStatus("loading")
99
133
  setSsrData(parseData(data))
100
134
  setError(undefined)
@@ -109,6 +143,7 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
109
143
  return
110
144
  }
111
145
 
146
+ pendingLazyRefreshRef.current = false
112
147
  setStatus("loading")
113
148
  setError(undefined)
114
149
 
@@ -139,7 +174,7 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
139
174
  setStatus("loaded")
140
175
  }, [status, context, fetcher, loader, url, params, parseData, name, cacheSet, logger])
141
176
 
142
- const checkCacheVersions = useCallback(
177
+ const cacheVersionsCheck = useCallback(
143
178
  async (versions) => {
144
179
  logger.verbose(
145
180
  `[miolo-react][ssr][${name}] Backend versions received: ${JSON.stringify(versions)}`
@@ -223,30 +258,68 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
223
258
  }
224
259
  }, [ssrDataFromContext, cacheSet])
225
260
 
261
+ const handlersRef = useRef({})
262
+
263
+ useEffect(() => {
264
+ handlersRef.current = {
265
+ cacheVersionsCheck,
266
+ cacheInvalidate,
267
+ refreshSsrData,
268
+ refreshSsrDataLazy: () => {
269
+ pendingLazyRefreshRef.current = true
270
+ }
271
+ }
272
+ })
273
+
274
+ useEffect(() => {
275
+ if (cache === true) {
276
+ patchHistory()
277
+ }
278
+
279
+ const onNav = () => {
280
+ if (pendingLazyRefreshRef.current) {
281
+ logger.verbose(
282
+ `[miolo-react][ssr][${name}] navigation detected, doing pending lazy refresh`
283
+ )
284
+ pendingLazyRefreshRef.current = false
285
+ refreshSsrData()
286
+ }
287
+ }
288
+ window.addEventListener("miolo-navigation", onNav)
289
+ return () => {
290
+ window.removeEventListener("miolo-navigation", onNav)
291
+ }
292
+ }, [cache, name, logger, refreshSsrData])
293
+
226
294
  useEffect(() => {
227
295
  if (!socket || cache !== true) {
228
296
  return
229
297
  }
230
298
 
231
- const onConnect = () => {
232
- logger.verbose(`[miolo-react][ssr][${name}] Socket connected, subscribing`)
233
- socket.emit("ssr-subscribe", name)
234
- logger.verbose(`[miolo-react][ssr][${name}] Asking for ssr-versions`)
235
- socket.emit("ssr-versions")
299
+ const currentCount = globalSocketState.rooms.get(name) || 0
300
+ globalSocketState.rooms.set(name, currentCount + 1)
301
+
302
+ const pendingTimer = globalSocketState.unsubscribeTimers.get(name)
303
+ if (pendingTimer) {
304
+ clearTimeout(pendingTimer)
305
+ globalSocketState.unsubscribeTimers.delete(name)
236
306
  }
237
307
 
238
- const onInvalidate = async (data) => {
239
- if (data.name !== name) return
308
+ const requestSubscribeAndVersions = () => {
309
+ const now = Date.now()
310
+ const lastSub = globalSocketState.lastSubscribeEmitted.get(name) || 0
240
311
 
241
- logger.verbose(`[miolo-react][ssr][${name}] ssr-invalidate ${JSON.stringify(data)}`)
242
- if (data.exclude_socket_id && data.exclude_socket_id === socket.id) {
243
- logger.verbose(
244
- `[miolo-react][ssr][${name}] ssr-invalidate ${data.name} ignored for socketid ${socket.id}`
245
- )
246
- return
312
+ if (now - lastSub > 100) {
313
+ globalSocketState.lastSubscribeEmitted.set(name, now)
314
+ logger.verbose(`[miolo-react][ssr][${name}] Socket connected, subscribing`)
315
+ socket.emit("ssr-subscribe", name)
316
+ }
317
+
318
+ if (now - globalSocketState.versionsRequestedAt > 500) {
319
+ globalSocketState.versionsRequestedAt = now
320
+ logger.verbose(`[miolo-react][ssr][${name}] Asking for ssr-versions`)
321
+ socket.emit("ssr-versions")
247
322
  }
248
- logger.info(`[miolo-react][ssr][${name}] ssr-invalidate ${data.name}`)
249
- await cacheInvalidate()
250
323
  }
251
324
 
252
325
  const onRefresh = async (data) => {
@@ -261,31 +334,66 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
261
334
  )
262
335
  return
263
336
  }
264
- logger.info(`[miolo-react][ssr][${name}] ssr-refresh ${data.name}`)
265
- await cacheInvalidate()
266
- refreshSsrData()
337
+ if (data.only_socket_id && data.only_socket_id !== socket.id) {
338
+ logger.verbose(
339
+ `[miolo-react][ssr][${name}] ssr-refresh ${data.name} ignored for socketid ${socket.id} (only_socket_id mismatch)`
340
+ )
341
+ return
342
+ }
343
+
344
+ logger.info(
345
+ `[miolo-react][ssr][${name}] ssr-refresh ${data.name}${data.lazy ? " (lazy)" : ""}`
346
+ )
347
+ await handlersRef.current.cacheInvalidate()
348
+
349
+ if (!data.lazy) {
350
+ handlersRef.current.refreshSsrData()
351
+ } else {
352
+ if (handlersRef.current.refreshSsrDataLazy) {
353
+ handlersRef.current.refreshSsrDataLazy()
354
+ }
355
+ }
356
+ }
357
+
358
+ const onVersions = (versions) => {
359
+ if (handlersRef.current.cacheVersionsCheck) {
360
+ handlersRef.current.cacheVersionsCheck(versions)
361
+ }
267
362
  }
268
363
 
269
364
  logger.verbose(`[miolo-react][ssr][${name}] Attaching ssr/cache socket handlers`)
270
365
 
271
366
  if (socket.connected) {
272
- onConnect()
367
+ requestSubscribeAndVersions()
273
368
  }
274
369
 
275
- socket.on("connect", onConnect)
276
- socket.on("ssr-versions", checkCacheVersions)
277
- socket.on("ssr-invalidate", onInvalidate)
370
+ socket.on("connect", requestSubscribeAndVersions)
371
+ socket.on("ssr-versions", onVersions)
278
372
  socket.on("ssr-refresh", onRefresh)
279
373
 
280
374
  return () => {
281
375
  logger.verbose(`[miolo-react][ssr][${name}] Detaching ssr/cache socket handlers`)
282
- socket.emit("ssr-unsubscribe", name)
283
- socket.off("connect", onConnect)
284
- socket.off("ssr-versions", checkCacheVersions)
285
- socket.off("ssr-invalidate", onInvalidate)
376
+
377
+ const count = globalSocketState.rooms.get(name) || 0
378
+ if (count > 0) {
379
+ globalSocketState.rooms.set(name, count - 1)
380
+ if (count - 1 === 0) {
381
+ const timer = setTimeout(() => {
382
+ if ((globalSocketState.rooms.get(name) || 0) === 0) {
383
+ socket.emit("ssr-unsubscribe", name)
384
+ globalSocketState.lastSubscribeEmitted.set(name, 0)
385
+ }
386
+ globalSocketState.unsubscribeTimers.delete(name)
387
+ }, 100)
388
+ globalSocketState.unsubscribeTimers.set(name, timer)
389
+ }
390
+ }
391
+
392
+ socket.off("connect", requestSubscribeAndVersions)
393
+ socket.off("ssr-versions", onVersions)
286
394
  socket.off("ssr-refresh", onRefresh)
287
395
  }
288
- }, [name, cache, socket, checkCacheVersions, logger, cacheInvalidate, refreshSsrData])
396
+ }, [name, cache, socket, logger])
289
397
 
290
398
  useOnWindowFocus(() => {
291
399
  if (cache !== true) {
@@ -297,7 +405,11 @@ const useSsrDataOrReload = (context, miolo, name, options) => {
297
405
  logger.verbose(
298
406
  `[miolo-react][ssr][${name}] Window focused, checking versions (socket id is ${socket.id})`
299
407
  )
300
- socket.emit("ssr-versions")
408
+ const now = Date.now()
409
+ if (now - globalSocketState.versionsRequestedAt > 500) {
410
+ globalSocketState.versionsRequestedAt = now
411
+ socket.emit("ssr-versions")
412
+ }
301
413
  }, [name, cache, logger, socket])
302
414
 
303
415
  return {