@praxisjs/core 2.0.0 → 2.1.0
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/CHANGELOG.md +10 -0
- package/dist/__tests__/resource-server-pass.test.d.ts +2 -0
- package/dist/__tests__/resource-server-pass.test.d.ts.map +1 -0
- package/dist/__tests__/resource-server-pass.test.js +78 -0
- package/dist/__tests__/resource-server-pass.test.js.map +1 -0
- package/dist/__tests__/synced.test.js +6 -7
- package/dist/__tests__/synced.test.js.map +1 -1
- package/dist/async/resource-cache.d.ts +7 -0
- package/dist/async/resource-cache.d.ts.map +1 -1
- package/dist/async/resource-cache.js +18 -0
- package/dist/async/resource-cache.js.map +1 -1
- package/dist/async/resource.d.ts +7 -0
- package/dist/async/resource.d.ts.map +1 -1
- package/dist/async/resource.js +16 -1
- package/dist/async/resource.js.map +1 -1
- package/dist/async/server-mode.d.ts +10 -0
- package/dist/async/server-mode.d.ts.map +1 -0
- package/dist/async/server-mode.js +15 -0
- package/dist/async/server-mode.js.map +1 -0
- package/dist/internal.d.ts +3 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +3 -2
- package/dist/internal.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/resource-server-pass.test.ts +90 -0
- package/src/async/resource-cache.ts +20 -0
- package/src/async/resource.ts +17 -0
- package/src/async/server-mode.ts +16 -0
- package/src/internal.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @praxisjs/core
|
|
2
2
|
|
|
3
|
+
## 2.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1ec5b2f: Add a resource settle barrier and a server-render-pass flag for `@praxisjs/ssg`.
|
|
8
|
+
|
|
9
|
+
`flushPendingResources()` (from `@praxisjs/core/internal`) awaits every `resource()` fetch — keyed or not — that starts while a server render pass is active, including ones triggered by resources that themselves settle while waiting. `setServerRenderPass()` / `isServerRenderPass()` mark that pass; both are no-ops outside of it, so client-only apps see zero behavior or performance change.
|
|
10
|
+
|
|
11
|
+
Also expose `trackPendingResource()` from `@praxisjs/core/internal`, so other framework packages can register their own in-flight async work (not just `resource()` calls) against the same settle barrier — used by `@praxisjs/router` to track lazy route/layout resolution during a server render pass.
|
|
12
|
+
|
|
3
13
|
## 2.0.0
|
|
4
14
|
|
|
5
15
|
### Major Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-server-pass.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/resource-server-pass.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { flushPendingResources, resource } from "../async/resource";
|
|
3
|
+
import { _clearCache, getPendingResources } from "../async/resource-cache";
|
|
4
|
+
import { setServerRenderPass, isServerRenderPass } from "../async/server-mode";
|
|
5
|
+
describe("server render pass — flushPendingResources", () => {
|
|
6
|
+
beforeEach(() => { _clearCache(); });
|
|
7
|
+
afterEach(() => { setServerRenderPass(false); });
|
|
8
|
+
it("is a no-op when no server pass is active", async () => {
|
|
9
|
+
setServerRenderPass(false);
|
|
10
|
+
const r = resource(() => new Promise(() => { }));
|
|
11
|
+
expect(getPendingResources().size).toBe(0);
|
|
12
|
+
await flushPendingResources();
|
|
13
|
+
// Untouched — resource() never settled and flush didn't wait for it.
|
|
14
|
+
expect(r.status()).toBe("pending");
|
|
15
|
+
});
|
|
16
|
+
it("resolves immediately when nothing is pending", async () => {
|
|
17
|
+
setServerRenderPass(true);
|
|
18
|
+
await expect(flushPendingResources()).resolves.toBeUndefined();
|
|
19
|
+
});
|
|
20
|
+
it("tracks isServerRenderPass() state via the setter", () => {
|
|
21
|
+
expect(isServerRenderPass()).toBe(false);
|
|
22
|
+
setServerRenderPass(true);
|
|
23
|
+
expect(isServerRenderPass()).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
it("awaits an unkeyed resource() (e.g. @Collection) before returning", async () => {
|
|
26
|
+
setServerRenderPass(true);
|
|
27
|
+
const r = resource(() => new Promise((res) => { setTimeout(() => { res("content"); }, 5); }));
|
|
28
|
+
await flushPendingResources();
|
|
29
|
+
expect(r.status()).toBe("success");
|
|
30
|
+
expect(r.data()).toBe("content");
|
|
31
|
+
});
|
|
32
|
+
it("awaits a keyed resource() too", async () => {
|
|
33
|
+
setServerRenderPass(true);
|
|
34
|
+
const r = resource(() => Promise.resolve("keyed-value"), { key: "ssg-key" });
|
|
35
|
+
await flushPendingResources();
|
|
36
|
+
expect(r.status()).toBe("success");
|
|
37
|
+
expect(r.data()).toBe("keyed-value");
|
|
38
|
+
});
|
|
39
|
+
it("awaits multiple concurrently pending resources", async () => {
|
|
40
|
+
setServerRenderPass(true);
|
|
41
|
+
const r1 = resource(() => new Promise((res) => { setTimeout(() => { res(1); }, 5); }));
|
|
42
|
+
const r2 = resource(() => new Promise((res) => { setTimeout(() => { res(2); }, 10); }));
|
|
43
|
+
await flushPendingResources();
|
|
44
|
+
expect(r1.data()).toBe(1);
|
|
45
|
+
expect(r2.data()).toBe(2);
|
|
46
|
+
});
|
|
47
|
+
it("fixed-point loop: awaits a resource created while an earlier one settles", async () => {
|
|
48
|
+
setServerRenderPass(true);
|
|
49
|
+
let second;
|
|
50
|
+
// Simulates a component that, upon its first resource resolving, creates a
|
|
51
|
+
// second resource (e.g. a detail page fetching related content) — the new
|
|
52
|
+
// promise must still be picked up even though it didn't exist yet when
|
|
53
|
+
// flushPendingResources() started its first pass.
|
|
54
|
+
const first = resource(() => new Promise((res) => {
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
res("first");
|
|
57
|
+
second = resource(() => new Promise((res2) => { setTimeout(() => { res2("second"); }, 5); }));
|
|
58
|
+
}, 5);
|
|
59
|
+
}));
|
|
60
|
+
await flushPendingResources();
|
|
61
|
+
expect(first.status()).toBe("success");
|
|
62
|
+
expect(second?.status()).toBe("success");
|
|
63
|
+
expect(second?.data()).toBe("second");
|
|
64
|
+
});
|
|
65
|
+
it("does not leave stale entries after resources settle", async () => {
|
|
66
|
+
setServerRenderPass(true);
|
|
67
|
+
resource(() => Promise.resolve("done"));
|
|
68
|
+
await flushPendingResources();
|
|
69
|
+
expect(getPendingResources().size).toBe(0);
|
|
70
|
+
});
|
|
71
|
+
it("a rejected resource does not hang the flush", async () => {
|
|
72
|
+
setServerRenderPass(true);
|
|
73
|
+
const r = resource(() => Promise.reject(new Error("boom")));
|
|
74
|
+
await expect(flushPendingResources()).resolves.toBeUndefined();
|
|
75
|
+
expect(r.status()).toBe("error");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=resource-server-pass.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-server-pass.test.js","sourceRoot":"","sources":["../../src/__tests__/resource-server-pass.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,11 +3,12 @@ import { syncedSignal } from "../signal/synced";
|
|
|
3
3
|
import { effect } from "../signal/effect";
|
|
4
4
|
// BroadcastChannel mock
|
|
5
5
|
class MockBroadcastChannel {
|
|
6
|
-
static
|
|
7
|
-
static
|
|
6
|
+
static instances = [];
|
|
7
|
+
static byChannel = new Map();
|
|
8
|
+
onmessage = null;
|
|
9
|
+
name;
|
|
10
|
+
closed = false;
|
|
8
11
|
constructor(name) {
|
|
9
|
-
this.onmessage = null;
|
|
10
|
-
this.closed = false;
|
|
11
12
|
this.name = name;
|
|
12
13
|
MockBroadcastChannel.instances.push(this);
|
|
13
14
|
if (!MockBroadcastChannel.byChannel.has(name)) {
|
|
@@ -119,9 +120,7 @@ describe("syncedSignal", () => {
|
|
|
119
120
|
// Use a self-delivering channel that echoes to itself during postMessage.
|
|
120
121
|
// This covers the `if (posting) return;` branch in synced.ts.
|
|
121
122
|
class SelfEchoChannel {
|
|
122
|
-
|
|
123
|
-
this.onmessage = null;
|
|
124
|
-
}
|
|
123
|
+
onmessage = null;
|
|
125
124
|
postMessage(data) {
|
|
126
125
|
this.onmessage?.(new MessageEvent("message", { data }));
|
|
127
126
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synced.test.js","sourceRoot":"","sources":["../../src/__tests__/synced.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,wBAAwB;AACxB,MAAM,oBAAoB;
|
|
1
|
+
{"version":3,"file":"synced.test.js","sourceRoot":"","sources":["../../src/__tests__/synced.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,13 @@ export declare function unregisterResource(key: string, refetch: () => void): vo
|
|
|
15
15
|
* every active resource registered under that key to refetch.
|
|
16
16
|
*/
|
|
17
17
|
export declare function invalidateResource(key: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Registers `promise` as pending while a server render pass is active (no-op otherwise,
|
|
20
|
+
* so client-side resource() calls never pay this cost). Self-removes on settle.
|
|
21
|
+
*/
|
|
22
|
+
export declare function trackPendingResource(promise: Promise<unknown>): void;
|
|
23
|
+
/** Snapshot of currently in-flight resource promises tracked during a server render pass. */
|
|
24
|
+
export declare function getPendingResources(): ReadonlySet<Promise<unknown>>;
|
|
18
25
|
/** Resets all cache state. Intended for use in tests only. */
|
|
19
26
|
export declare function _clearCache(): void;
|
|
20
27
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-cache.d.ts","sourceRoot":"","sources":["../../src/async/resource-cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resource-cache.d.ts","sourceRoot":"","sources":["../../src/async/resource-cache.ts"],"names":[],"mappings":"AAEA,UAAU,UAAU;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAEjE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAE9D;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,SAAS,CAErE;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAExE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAOvE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAEzE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAIpD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAKpE;AAED,6FAA6F;AAC7F,wBAAgB,mBAAmB,IAAI,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAEnE;AAED,8DAA8D;AAC9D,wBAAgB,WAAW,IAAI,IAAI,CAKlC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { isServerRenderPass } from "./server-mode";
|
|
1
2
|
const _cache = new Map();
|
|
2
3
|
const _inflight = new Map();
|
|
3
4
|
const _registry = new Map();
|
|
5
|
+
const _pendingResources = new Set();
|
|
4
6
|
export function getCacheEntry(key) {
|
|
5
7
|
return _cache.get(key);
|
|
6
8
|
}
|
|
@@ -39,10 +41,26 @@ export function invalidateResource(key) {
|
|
|
39
41
|
deleteInflight(key);
|
|
40
42
|
_registry.get(key)?.forEach((fn) => { fn(); });
|
|
41
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Registers `promise` as pending while a server render pass is active (no-op otherwise,
|
|
46
|
+
* so client-side resource() calls never pay this cost). Self-removes on settle.
|
|
47
|
+
*/
|
|
48
|
+
export function trackPendingResource(promise) {
|
|
49
|
+
if (!isServerRenderPass())
|
|
50
|
+
return;
|
|
51
|
+
_pendingResources.add(promise);
|
|
52
|
+
const cleanup = () => { _pendingResources.delete(promise); };
|
|
53
|
+
promise.then(cleanup, cleanup);
|
|
54
|
+
}
|
|
55
|
+
/** Snapshot of currently in-flight resource promises tracked during a server render pass. */
|
|
56
|
+
export function getPendingResources() {
|
|
57
|
+
return _pendingResources;
|
|
58
|
+
}
|
|
42
59
|
/** Resets all cache state. Intended for use in tests only. */
|
|
43
60
|
export function _clearCache() {
|
|
44
61
|
_cache.clear();
|
|
45
62
|
_inflight.clear();
|
|
46
63
|
_registry.clear();
|
|
64
|
+
_pendingResources.clear();
|
|
47
65
|
}
|
|
48
66
|
//# sourceMappingURL=resource-cache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-cache.js","sourceRoot":"","sources":["../../src/async/resource-cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resource-cache.js","sourceRoot":"","sources":["../../src/async/resource-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAOnD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;AAC7C,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;AACtD,MAAM,SAAS,GAAG,IAAI,GAAG,EAA2B,CAAC;AACrD,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAoB,CAAC;AAEtD,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,IAAa;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,OAAO,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,OAAyB;IAChE,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,OAAmB;IAC/D,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;QAChB,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC1B,CAAC;IACD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,OAAmB;IACjE,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACtB,cAAc,CAAC,GAAG,CAAC,CAAC;IACpB,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAyB;IAC5D,IAAI,CAAC,kBAAkB,EAAE;QAAE,OAAO;IAClC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,GAAS,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,mBAAmB;IACjC,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,WAAW;IACzB,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,iBAAiB,CAAC,KAAK,EAAE,CAAC;AAC5B,CAAC"}
|
package/dist/async/resource.d.ts
CHANGED
|
@@ -20,4 +20,11 @@ export interface ResourceOptions<T> {
|
|
|
20
20
|
}
|
|
21
21
|
export declare function resource<T>(fetcher: () => Promise<T>, options?: ResourceOptions<T>): Resource<T>;
|
|
22
22
|
export declare function createResource<P, T>(param: Signal<P> | Computed<P>, fetcher: (param: P) => Promise<T>, options?: ResourceOptions<T>): Resource<T>;
|
|
23
|
+
/**
|
|
24
|
+
* Awaits every resource fetch tracked during a server render pass (see
|
|
25
|
+
* `setServerRenderPass`), including ones triggered by resources that themselves
|
|
26
|
+
* settle while waiting (fixed-point loop). No-op — resolves immediately — when
|
|
27
|
+
* nothing is pending or tracking isn't active.
|
|
28
|
+
*/
|
|
29
|
+
export declare function flushPendingResources(): Promise<void>;
|
|
23
30
|
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/async/resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/async/resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAgBzD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtE,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;IAC1C,OAAO,IAAI,IAAI,CAAC;IAChB,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACtB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,CAAC,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,QAAQ,CAAC,CAAC,EACxB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,OAAO,GAAE,eAAe,CAAC,CAAC,CAAM,GAC/B,QAAQ,CAAC,CAAC,CAAC,CAqJb;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EACjC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,EAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EACjC,OAAO,GAAE,eAAe,CAAC,CAAC,CAAM,GAC/B,QAAQ,CAAC,CAAC,CAAC,CAEb;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM3D"}
|
package/dist/async/resource.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { computed, signal } from "../signal";
|
|
2
|
-
import { getCacheEntry, setCacheEntry, deleteInflight, getInflight, setInflight, registerResource, unregisterResource, } from "./resource-cache";
|
|
2
|
+
import { getCacheEntry, setCacheEntry, deleteInflight, getInflight, setInflight, registerResource, unregisterResource, trackPendingResource, getPendingResources, } from "./resource-cache";
|
|
3
3
|
import { effect, untrack } from "../signal/effect";
|
|
4
4
|
export function resource(fetcher, options = {}) {
|
|
5
5
|
const { initialData = null, immediate = true, keepPreviousData = false, key, staleTime = 0, refetchOnFocus = false, } = options;
|
|
@@ -10,6 +10,7 @@ export function resource(fetcher, options = {}) {
|
|
|
10
10
|
const _status = signal(cached ? "success" : "idle");
|
|
11
11
|
let _runId = 0;
|
|
12
12
|
function _execute(fn) {
|
|
13
|
+
trackPendingResource(fn);
|
|
13
14
|
const currentRunId = ++_runId;
|
|
14
15
|
function clearInflight() {
|
|
15
16
|
if (key && getInflight(key) === fn)
|
|
@@ -140,4 +141,18 @@ export function resource(fetcher, options = {}) {
|
|
|
140
141
|
export function createResource(param, fetcher, options = {}) {
|
|
141
142
|
return resource(() => fetcher(param()), options);
|
|
142
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Awaits every resource fetch tracked during a server render pass (see
|
|
146
|
+
* `setServerRenderPass`), including ones triggered by resources that themselves
|
|
147
|
+
* settle while waiting (fixed-point loop). No-op — resolves immediately — when
|
|
148
|
+
* nothing is pending or tracking isn't active.
|
|
149
|
+
*/
|
|
150
|
+
export async function flushPendingResources() {
|
|
151
|
+
for (;;) {
|
|
152
|
+
const pending = Array.from(getPendingResources());
|
|
153
|
+
if (pending.length === 0)
|
|
154
|
+
return;
|
|
155
|
+
await Promise.allSettled(pending);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
143
158
|
//# sourceMappingURL=resource.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/async/resource.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/async/resource.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marks whether the current process is doing a build-time server/SSG render pass
|
|
3
|
+
* (as opposed to a normal browser render). Consumed by `resource-cache` (gates
|
|
4
|
+
* pending-promise tracking for `flushPendingResources`) and by `@praxisjs/runtime`'s
|
|
5
|
+
* `Portal`, which skips mounting entirely during a server pass so its content
|
|
6
|
+
* never gets baked into static HTML (it mounts normally once on the client).
|
|
7
|
+
*/
|
|
8
|
+
export declare function setServerRenderPass(active: boolean): void;
|
|
9
|
+
export declare function isServerRenderPass(): boolean;
|
|
10
|
+
//# sourceMappingURL=server-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-mode.d.ts","sourceRoot":"","sources":["../../src/async/server-mode.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAEzD;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
let _serverRenderPass = false;
|
|
2
|
+
/**
|
|
3
|
+
* Marks whether the current process is doing a build-time server/SSG render pass
|
|
4
|
+
* (as opposed to a normal browser render). Consumed by `resource-cache` (gates
|
|
5
|
+
* pending-promise tracking for `flushPendingResources`) and by `@praxisjs/runtime`'s
|
|
6
|
+
* `Portal`, which skips mounting entirely during a server pass so its content
|
|
7
|
+
* never gets baked into static HTML (it mounts normally once on the client).
|
|
8
|
+
*/
|
|
9
|
+
export function setServerRenderPass(active) {
|
|
10
|
+
_serverRenderPass = active;
|
|
11
|
+
}
|
|
12
|
+
export function isServerRenderPass() {
|
|
13
|
+
return _serverRenderPass;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=server-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-mode.js","sourceRoot":"","sources":["../../src/async/server-mode.ts"],"names":[],"mappings":"AAAA,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAe;IACjD,iBAAiB,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,iBAAiB,CAAC;AAC3B,CAAC"}
|
package/dist/internal.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { debounced, until, when, history, type HistoryElement, } from "./reactiv
|
|
|
2
2
|
export { signal, persistedSignal, syncedSignal, peek, computed, writableComputed, batch, effect, untrack, type PersistedSignalOptions, type SyncedSignal, } from "./signal";
|
|
3
3
|
export { RootComponent } from "./component";
|
|
4
4
|
export { componentPropsType, getComponentAnchor, getComponentDefault, getComponentDefaults, getComponentProps, getComponentRawProp, isComponentMounted, isStateDirty, markStateDirty, setComponentAnchor, setComponentDefault, setComponentMounted, setComponentProps, setStateDirty, } from "./component/internals";
|
|
5
|
-
export { resource, createResource, type ResourceStatus, type Resource, type ResourceOptions, } from "./async/resource";
|
|
6
|
-
export { invalidateResource, _clearCache } from "./async/resource-cache";
|
|
5
|
+
export { resource, createResource, flushPendingResources, type ResourceStatus, type Resource, type ResourceOptions, } from "./async/resource";
|
|
6
|
+
export { invalidateResource, trackPendingResource, _clearCache } from "./async/resource-cache";
|
|
7
|
+
export { setServerRenderPass, isServerRenderPass } from "./async/server-mode";
|
|
7
8
|
//# sourceMappingURL=internal.d.ts.map
|
package/dist/internal.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACJ,OAAO,EACP,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,eAAe,EACf,YAAY,EACZ,IAAI,EACJ,QAAQ,EACR,gBAAgB,EAChB,KAAK,EACL,MAAM,EACN,OAAO,EACP,KAAK,sBAAsB,EAC3B,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,QAAQ,EACR,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACJ,OAAO,EACP,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,eAAe,EACf,YAAY,EACZ,IAAI,EACJ,QAAQ,EACR,gBAAgB,EAChB,KAAK,EACL,MAAM,EACN,OAAO,EACP,KAAK,sBAAsB,EAC3B,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,QAAQ,EACR,cAAc,EACd,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC/F,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/internal.js
CHANGED
|
@@ -2,6 +2,7 @@ export { debounced, until, when, history, } from "./reactive";
|
|
|
2
2
|
export { signal, persistedSignal, syncedSignal, peek, computed, writableComputed, batch, effect, untrack, } from "./signal";
|
|
3
3
|
export { RootComponent } from "./component";
|
|
4
4
|
export { componentPropsType, getComponentAnchor, getComponentDefault, getComponentDefaults, getComponentProps, getComponentRawProp, isComponentMounted, isStateDirty, markStateDirty, setComponentAnchor, setComponentDefault, setComponentMounted, setComponentProps, setStateDirty, } from "./component/internals";
|
|
5
|
-
export { resource, createResource, } from "./async/resource";
|
|
6
|
-
export { invalidateResource, _clearCache } from "./async/resource-cache";
|
|
5
|
+
export { resource, createResource, flushPendingResources, } from "./async/resource";
|
|
6
|
+
export { invalidateResource, trackPendingResource, _clearCache } from "./async/resource-cache";
|
|
7
|
+
export { setServerRenderPass, isServerRenderPass } from "./async/server-mode";
|
|
7
8
|
//# sourceMappingURL=internal.js.map
|
package/dist/internal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACJ,OAAO,GAER,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,eAAe,EACf,YAAY,EACZ,IAAI,EACJ,QAAQ,EACR,gBAAgB,EAChB,KAAK,EACL,MAAM,EACN,OAAO,GAGR,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,QAAQ,EACR,cAAc,
|
|
1
|
+
{"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACJ,OAAO,GAER,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,eAAe,EACf,YAAY,EACZ,IAAI,EACJ,QAAQ,EACR,gBAAgB,EAChB,KAAK,EACL,MAAM,EACN,OAAO,GAGR,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,QAAQ,EACR,cAAc,EACd,qBAAqB,GAItB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC/F,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisjs/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"typescript": "^
|
|
18
|
+
"typescript": "^6.0.3"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@praxisjs/shared": "0.3.1"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { flushPendingResources, resource } from "../async/resource";
|
|
4
|
+
import { _clearCache, getPendingResources } from "../async/resource-cache";
|
|
5
|
+
import { setServerRenderPass, isServerRenderPass } from "../async/server-mode";
|
|
6
|
+
|
|
7
|
+
describe("server render pass — flushPendingResources", () => {
|
|
8
|
+
beforeEach(() => { _clearCache(); });
|
|
9
|
+
afterEach(() => { setServerRenderPass(false); });
|
|
10
|
+
|
|
11
|
+
it("is a no-op when no server pass is active", async () => {
|
|
12
|
+
setServerRenderPass(false);
|
|
13
|
+
const r = resource(() => new Promise<string>(() => {}));
|
|
14
|
+
expect(getPendingResources().size).toBe(0);
|
|
15
|
+
await flushPendingResources();
|
|
16
|
+
// Untouched — resource() never settled and flush didn't wait for it.
|
|
17
|
+
expect(r.status()).toBe("pending");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("resolves immediately when nothing is pending", async () => {
|
|
21
|
+
setServerRenderPass(true);
|
|
22
|
+
await expect(flushPendingResources()).resolves.toBeUndefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("tracks isServerRenderPass() state via the setter", () => {
|
|
26
|
+
expect(isServerRenderPass()).toBe(false);
|
|
27
|
+
setServerRenderPass(true);
|
|
28
|
+
expect(isServerRenderPass()).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("awaits an unkeyed resource() (e.g. @Collection) before returning", async () => {
|
|
32
|
+
setServerRenderPass(true);
|
|
33
|
+
const r = resource(() => new Promise<string>((res) => { setTimeout(() => { res("content"); }, 5); }));
|
|
34
|
+
await flushPendingResources();
|
|
35
|
+
expect(r.status()).toBe("success");
|
|
36
|
+
expect(r.data()).toBe("content");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("awaits a keyed resource() too", async () => {
|
|
40
|
+
setServerRenderPass(true);
|
|
41
|
+
const r = resource(() => Promise.resolve("keyed-value"), { key: "ssg-key" });
|
|
42
|
+
await flushPendingResources();
|
|
43
|
+
expect(r.status()).toBe("success");
|
|
44
|
+
expect(r.data()).toBe("keyed-value");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("awaits multiple concurrently pending resources", async () => {
|
|
48
|
+
setServerRenderPass(true);
|
|
49
|
+
const r1 = resource(() => new Promise<number>((res) => { setTimeout(() => { res(1); }, 5); }));
|
|
50
|
+
const r2 = resource(() => new Promise<number>((res) => { setTimeout(() => { res(2); }, 10); }));
|
|
51
|
+
await flushPendingResources();
|
|
52
|
+
expect(r1.data()).toBe(1);
|
|
53
|
+
expect(r2.data()).toBe(2);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("fixed-point loop: awaits a resource created while an earlier one settles", async () => {
|
|
57
|
+
setServerRenderPass(true);
|
|
58
|
+
let second: ReturnType<typeof resource> | undefined;
|
|
59
|
+
|
|
60
|
+
// Simulates a component that, upon its first resource resolving, creates a
|
|
61
|
+
// second resource (e.g. a detail page fetching related content) — the new
|
|
62
|
+
// promise must still be picked up even though it didn't exist yet when
|
|
63
|
+
// flushPendingResources() started its first pass.
|
|
64
|
+
const first = resource(() => new Promise<string>((res) => {
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
res("first");
|
|
67
|
+
second = resource(() => new Promise<string>((res2) => { setTimeout(() => { res2("second"); }, 5); }));
|
|
68
|
+
}, 5);
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
await flushPendingResources();
|
|
72
|
+
expect(first.status()).toBe("success");
|
|
73
|
+
expect(second?.status()).toBe("success");
|
|
74
|
+
expect(second?.data()).toBe("second");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("does not leave stale entries after resources settle", async () => {
|
|
78
|
+
setServerRenderPass(true);
|
|
79
|
+
resource(() => Promise.resolve("done"));
|
|
80
|
+
await flushPendingResources();
|
|
81
|
+
expect(getPendingResources().size).toBe(0);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("a rejected resource does not hang the flush", async () => {
|
|
85
|
+
setServerRenderPass(true);
|
|
86
|
+
const r = resource(() => Promise.reject(new Error("boom")));
|
|
87
|
+
await expect(flushPendingResources()).resolves.toBeUndefined();
|
|
88
|
+
expect(r.status()).toBe("error");
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isServerRenderPass } from "./server-mode";
|
|
2
|
+
|
|
1
3
|
interface CacheEntry {
|
|
2
4
|
data: unknown;
|
|
3
5
|
timestamp: number;
|
|
@@ -6,6 +8,7 @@ interface CacheEntry {
|
|
|
6
8
|
const _cache = new Map<string, CacheEntry>();
|
|
7
9
|
const _inflight = new Map<string, Promise<unknown>>();
|
|
8
10
|
const _registry = new Map<string, Set<() => void>>();
|
|
11
|
+
const _pendingResources = new Set<Promise<unknown>>();
|
|
9
12
|
|
|
10
13
|
export function getCacheEntry(key: string): CacheEntry | undefined {
|
|
11
14
|
return _cache.get(key);
|
|
@@ -54,9 +57,26 @@ export function invalidateResource(key: string): void {
|
|
|
54
57
|
_registry.get(key)?.forEach((fn) => { fn(); });
|
|
55
58
|
}
|
|
56
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Registers `promise` as pending while a server render pass is active (no-op otherwise,
|
|
62
|
+
* so client-side resource() calls never pay this cost). Self-removes on settle.
|
|
63
|
+
*/
|
|
64
|
+
export function trackPendingResource(promise: Promise<unknown>): void {
|
|
65
|
+
if (!isServerRenderPass()) return;
|
|
66
|
+
_pendingResources.add(promise);
|
|
67
|
+
const cleanup = (): void => { _pendingResources.delete(promise); };
|
|
68
|
+
promise.then(cleanup, cleanup);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Snapshot of currently in-flight resource promises tracked during a server render pass. */
|
|
72
|
+
export function getPendingResources(): ReadonlySet<Promise<unknown>> {
|
|
73
|
+
return _pendingResources;
|
|
74
|
+
}
|
|
75
|
+
|
|
57
76
|
/** Resets all cache state. Intended for use in tests only. */
|
|
58
77
|
export function _clearCache(): void {
|
|
59
78
|
_cache.clear();
|
|
60
79
|
_inflight.clear();
|
|
61
80
|
_registry.clear();
|
|
81
|
+
_pendingResources.clear();
|
|
62
82
|
}
|
package/src/async/resource.ts
CHANGED
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
setInflight,
|
|
10
10
|
registerResource,
|
|
11
11
|
unregisterResource,
|
|
12
|
+
trackPendingResource,
|
|
13
|
+
getPendingResources,
|
|
12
14
|
} from "./resource-cache";
|
|
13
15
|
import { effect, untrack } from "../signal/effect";
|
|
14
16
|
|
|
@@ -58,6 +60,7 @@ export function resource<T>(
|
|
|
58
60
|
let _runId = 0;
|
|
59
61
|
|
|
60
62
|
function _execute(fn: Promise<T>): void {
|
|
63
|
+
trackPendingResource(fn);
|
|
61
64
|
const currentRunId = ++_runId;
|
|
62
65
|
|
|
63
66
|
function clearInflight(): void {
|
|
@@ -194,3 +197,17 @@ export function createResource<P, T>(
|
|
|
194
197
|
): Resource<T> {
|
|
195
198
|
return resource(() => fetcher(param()), options);
|
|
196
199
|
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Awaits every resource fetch tracked during a server render pass (see
|
|
203
|
+
* `setServerRenderPass`), including ones triggered by resources that themselves
|
|
204
|
+
* settle while waiting (fixed-point loop). No-op — resolves immediately — when
|
|
205
|
+
* nothing is pending or tracking isn't active.
|
|
206
|
+
*/
|
|
207
|
+
export async function flushPendingResources(): Promise<void> {
|
|
208
|
+
for (;;) {
|
|
209
|
+
const pending = Array.from(getPendingResources());
|
|
210
|
+
if (pending.length === 0) return;
|
|
211
|
+
await Promise.allSettled(pending);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
let _serverRenderPass = false;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Marks whether the current process is doing a build-time server/SSG render pass
|
|
5
|
+
* (as opposed to a normal browser render). Consumed by `resource-cache` (gates
|
|
6
|
+
* pending-promise tracking for `flushPendingResources`) and by `@praxisjs/runtime`'s
|
|
7
|
+
* `Portal`, which skips mounting entirely during a server pass so its content
|
|
8
|
+
* never gets baked into static HTML (it mounts normally once on the client).
|
|
9
|
+
*/
|
|
10
|
+
export function setServerRenderPass(active: boolean): void {
|
|
11
|
+
_serverRenderPass = active;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function isServerRenderPass(): boolean {
|
|
15
|
+
return _serverRenderPass;
|
|
16
|
+
}
|
package/src/internal.ts
CHANGED
|
@@ -38,8 +38,10 @@ export {
|
|
|
38
38
|
export {
|
|
39
39
|
resource,
|
|
40
40
|
createResource,
|
|
41
|
+
flushPendingResources,
|
|
41
42
|
type ResourceStatus,
|
|
42
43
|
type Resource,
|
|
43
44
|
type ResourceOptions,
|
|
44
45
|
} from "./async/resource";
|
|
45
|
-
export { invalidateResource, _clearCache } from "./async/resource-cache";
|
|
46
|
+
export { invalidateResource, trackPendingResource, _clearCache } from "./async/resource-cache";
|
|
47
|
+
export { setServerRenderPass, isServerRenderPass } from "./async/server-mode";
|