@torpor/view 1.0.3 → 1.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/dist/{fromWebSocket-DeB35Q4w.d.cts → AsyncOptions-BtMe2PAd.d.cts} +21 -2
- package/dist/AsyncOptions-BtMe2PAd.d.cts.map +1 -0
- package/dist/{fromWebSocket-B52kN3-W.d.mts → AsyncOptions-ClS1_ERX.d.mts} +21 -2
- package/dist/AsyncOptions-ClS1_ERX.d.mts.map +1 -0
- package/dist/{Effect-BTKurOpr.d.mts → Effect-DazmAdyC.d.mts} +3 -3
- package/dist/{Effect-BTKurOpr.d.mts.map → Effect-DazmAdyC.d.mts.map} +1 -1
- package/dist/{Effect-COl3aRJV.d.cts → Effect-Dewn7MLc.d.cts} +3 -3
- package/dist/{Effect-COl3aRJV.d.cts.map → Effect-Dewn7MLc.d.cts.map} +1 -1
- package/dist/compile.cjs +59 -13
- package/dist/compile.mjs +59 -13
- package/dist/compile.mjs.map +1 -1
- package/dist/dev.d.cts +1 -1
- package/dist/dev.d.mts +1 -1
- package/dist/index.cjs +60 -8
- package/dist/index.d.cts +23 -6
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +23 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +60 -8
- package/dist/index.mjs.map +1 -1
- package/dist/ssr.cjs +292 -4
- package/dist/ssr.d.cts +108 -9
- package/dist/ssr.d.cts.map +1 -1
- package/dist/ssr.d.mts +108 -9
- package/dist/ssr.d.mts.map +1 -1
- package/dist/ssr.mjs +291 -5
- package/dist/ssr.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/fromWebSocket-B52kN3-W.d.mts.map +0 -1
- package/dist/fromWebSocket-DeB35Q4w.d.cts.map +0 -1
|
@@ -87,5 +87,24 @@ declare function fromServer(url: string | (() => string)): StreamSource<MessageE
|
|
|
87
87
|
*/
|
|
88
88
|
declare function fromWebSocket(url: string | (() => string)): StreamSource<MessageEvent>;
|
|
89
89
|
//#endregion
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
//#region src/types/AsyncOptions.d.ts
|
|
91
|
+
/**
|
|
92
|
+
* Options for the `$async` getter primitive.
|
|
93
|
+
*/
|
|
94
|
+
interface AsyncOptions {
|
|
95
|
+
/**
|
|
96
|
+
* Where the value comes from. The default (`"client"`) starts the fetch
|
|
97
|
+
* after hydration; `"server"` fetches during SSR and ships the resolved
|
|
98
|
+
* value embedded in the HTML (see ASYNC.md → "Server rendering").
|
|
99
|
+
*/
|
|
100
|
+
source?: "client" | "server";
|
|
101
|
+
/**
|
|
102
|
+
* With `source: "server"`, how long (ms) the server waits for this
|
|
103
|
+
* getter's promise before the enclosing `@await` boundary degrades to its
|
|
104
|
+
* `with` branch and the client fetches instead. Defaults to 5000.
|
|
105
|
+
*/
|
|
106
|
+
timeout?: number;
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { StreamSource as a, buildClasses as c, fromElement as i, ClassValue as l, fromWebSocket as n, buildStyles as o, fromServer as r, StyleValue as s, AsyncOptions as t };
|
|
110
|
+
//# sourceMappingURL=AsyncOptions-BtMe2PAd.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsyncOptions-BtMe2PAd.d.cts","names":[],"sources":["../src/types/ClassValue.ts","../src/render/buildClasses.ts","../src/types/StyleValue.ts","../src/render/buildStyles.ts","../src/types/StreamSource.ts","../src/stream/fromElement.ts","../src/stream/fromServer.ts","../src/stream/fromWebSocket.ts","../src/types/AsyncOptions.ts"],"mappings":";;KAAK,sBAEF,6CACA,MAAM;;;iBCAe,aAAa,OAAO,YAAY;;;KCHnD,sBAEF,4CACA,MAAM;;;iBCCe,YAAY,OAAO;;;;;;;;;;;;;;;;;KCYtC,aAAa,MAAM,OAAO,OAAO,eAAe;;;;;;;;;;;;;;KCHhD,mBAAmB,qBAAqB;;;;;;;;;;;iBAYrB,YAAY,UAAU,QAAQ,OACrD,QAAQ,kBACR,eACE,aAAa;;;;;;;;;;;;;;;;;iBCZQ,WAAW,+BAA+B,aAAa;;;;;;;;;;;;;;;;;iBCAvD,cAAc,+BAA+B,aAAa;;;;;;UCbzD;;;;;;EAMxB;;;;;;EAOA"}
|
|
@@ -87,5 +87,24 @@ declare function fromServer(url: string | (() => string)): StreamSource<MessageE
|
|
|
87
87
|
*/
|
|
88
88
|
declare function fromWebSocket(url: string | (() => string)): StreamSource<MessageEvent>;
|
|
89
89
|
//#endregion
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
//#region src/types/AsyncOptions.d.ts
|
|
91
|
+
/**
|
|
92
|
+
* Options for the `$async` getter primitive.
|
|
93
|
+
*/
|
|
94
|
+
interface AsyncOptions {
|
|
95
|
+
/**
|
|
96
|
+
* Where the value comes from. The default (`"client"`) starts the fetch
|
|
97
|
+
* after hydration; `"server"` fetches during SSR and ships the resolved
|
|
98
|
+
* value embedded in the HTML (see ASYNC.md → "Server rendering").
|
|
99
|
+
*/
|
|
100
|
+
source?: "client" | "server";
|
|
101
|
+
/**
|
|
102
|
+
* With `source: "server"`, how long (ms) the server waits for this
|
|
103
|
+
* getter's promise before the enclosing `@await` boundary degrades to its
|
|
104
|
+
* `with` branch and the client fetches instead. Defaults to 5000.
|
|
105
|
+
*/
|
|
106
|
+
timeout?: number;
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { StreamSource as a, buildClasses as c, fromElement as i, ClassValue as l, fromWebSocket as n, buildStyles as o, fromServer as r, StyleValue as s, AsyncOptions as t };
|
|
110
|
+
//# sourceMappingURL=AsyncOptions-ClS1_ERX.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsyncOptions-ClS1_ERX.d.mts","names":[],"sources":["../src/types/ClassValue.ts","../src/render/buildClasses.ts","../src/types/StyleValue.ts","../src/render/buildStyles.ts","../src/types/StreamSource.ts","../src/stream/fromElement.ts","../src/stream/fromServer.ts","../src/stream/fromWebSocket.ts","../src/types/AsyncOptions.ts"],"mappings":";;KAAK,sBAEF,6CACA,MAAM;;;iBCAe,aAAa,OAAO,YAAY;;;KCHnD,sBAEF,4CACA,MAAM;;;iBCCe,YAAY,OAAO;;;;;;;;;;;;;;;;;KCYtC,aAAa,MAAM,OAAO,OAAO,eAAe;;;;;;;;;;;;;;KCHhD,mBAAmB,qBAAqB;;;;;;;;;;;iBAYrB,YAAY,UAAU,QAAQ,OACrD,QAAQ,kBACR,eACE,aAAa;;;;;;;;;;;;;;;;;iBCZQ,WAAW,+BAA+B,aAAa;;;;;;;;;;;;;;;;;iBCAvD,cAAc,+BAA+B,aAAa;;;;;;UCbzD;;;;;;EAMxB;;;;;;EAOA"}
|
|
@@ -168,7 +168,7 @@ interface Computed<T = any> {
|
|
|
168
168
|
/**
|
|
169
169
|
* True when the current suspend is a "bare refresh" — a re-fetch with no
|
|
170
170
|
* tracked dependency change, i.e. a silent `$refresh(fn, { silent: true })`
|
|
171
|
-
* (background revalidation), per ASYNC.md
|
|
171
|
+
* (background revalidation), per ASYNC.md → "Loud vs quiet")
|
|
172
172
|
* `$pending` reads this to stay quiet (return `false`) on silent refreshes,
|
|
173
173
|
* matching Solid's stale-while-revalidate default.
|
|
174
174
|
*
|
|
@@ -182,7 +182,7 @@ interface Computed<T = any> {
|
|
|
182
182
|
suspendQuiet: boolean;
|
|
183
183
|
/**
|
|
184
184
|
* The previously resolved value, retained across a refresh suspend for
|
|
185
|
-
* stale-while-revalidate (ASYNC.md
|
|
185
|
+
* stale-while-revalidate (ASYNC.md → "Stale-while-revalidate"). Maintained by `$async`'s
|
|
186
186
|
* generation-guarded settle handlers — set on resolve, cleared on
|
|
187
187
|
* rejection — so it always holds the last RESOLVED value, never a
|
|
188
188
|
* superseded run's in-flight promise (rapid prop changes would otherwise
|
|
@@ -378,4 +378,4 @@ interface Effect {
|
|
|
378
378
|
}
|
|
379
379
|
//#endregion
|
|
380
380
|
export { ProxySignal as i, Region as n, Computed as r, Effect as t };
|
|
381
|
-
//# sourceMappingURL=Effect-
|
|
381
|
+
//# sourceMappingURL=Effect-DazmAdyC.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Effect-
|
|
1
|
+
{"version":3,"file":"Effect-DazmAdyC.d.mts","names":[],"sources":["../src/types/constants.ts","../src/types/ProxySignal.ts","../src/types/Subscription.ts","../src/types/Computed.ts","../src/types/ErrorBoundary.ts","../src/types/Region.ts","../src/types/Effect.ts"],"mappings":";;;;;cAGa;;;;cAKA;;;;cAKA;;;;;;;UCNY;;;;EAIxB,aAAa;;;;EAKb,aAAa;;;;EAKb,oBAAoB;;;;EAKpB;;;;;;;;UClBwB;;;;EAIxB,QAAQ,cAAc;;;;EAKtB,QAAQ,WAAW;;;;;EAMnB,YAAY;;;;;EAMZ,YAAY;;;;;;;EAQZ,gBAAgB;;;;;;EAOhB;;;;;EAMA;;;;EAKA;;;;;;;;;UC/CwB,SAAS;;;;EAIjC,aAAa;;;;;;;;EASb;;;;EAKA,OAAO;;;;EAKP,WAAW;;;;EAKX,aAAa;;;;EAKb,aAAa;;;;;;;EAQb;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;EAQA;;;;;;;EAQA;;;;;;;;;EAUA;;;;;;;;;;;;;;;EAgBA;;;;;;;;;;;;;EAcA;;;;EAKA,UAAU;;;;EAKV;;;;;;;;;;UC3HwB;;;;;;EAMxB;;;;;EAMA;;;;;EAMA,QAAQ;;;;;;;;;EAUR,cAAc,cAAc;;;;UCnCJ;EACxB,WAAW;EACX,SAAS;EAET,gBAAgB;EAChB,YAAY;EACZ;;;;;EAMA,YAAY,IAAI;;;;EAKhB;;;;EAKA,SAAS;;;;;;;EAQT,gBAAgB;;;;;;;EAQhB;;;;;;EAOA;;;;;;;UCtCwB;;;;EAIxB,aAAa;;;;;EAMb,WAAW;;;;EAKX,SAAS;;;;EAKT,aAAa;EAKb,YAAY;;;;EAKZ;;;;;;EAOA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;EAWA,iBAAiB,IAAI;;;;EAKrB;;;;;;EAOA,SAAS;;;;;;EAOT,gBAAgB,cAAc;;;;;;;;;EAU9B;;;;;;;;;;;;;;;;EAiBA"}
|
|
@@ -168,7 +168,7 @@ interface Computed<T = any> {
|
|
|
168
168
|
/**
|
|
169
169
|
* True when the current suspend is a "bare refresh" — a re-fetch with no
|
|
170
170
|
* tracked dependency change, i.e. a silent `$refresh(fn, { silent: true })`
|
|
171
|
-
* (background revalidation), per ASYNC.md
|
|
171
|
+
* (background revalidation), per ASYNC.md → "Loud vs quiet")
|
|
172
172
|
* `$pending` reads this to stay quiet (return `false`) on silent refreshes,
|
|
173
173
|
* matching Solid's stale-while-revalidate default.
|
|
174
174
|
*
|
|
@@ -182,7 +182,7 @@ interface Computed<T = any> {
|
|
|
182
182
|
suspendQuiet: boolean;
|
|
183
183
|
/**
|
|
184
184
|
* The previously resolved value, retained across a refresh suspend for
|
|
185
|
-
* stale-while-revalidate (ASYNC.md
|
|
185
|
+
* stale-while-revalidate (ASYNC.md → "Stale-while-revalidate"). Maintained by `$async`'s
|
|
186
186
|
* generation-guarded settle handlers — set on resolve, cleared on
|
|
187
187
|
* rejection — so it always holds the last RESOLVED value, never a
|
|
188
188
|
* superseded run's in-flight promise (rapid prop changes would otherwise
|
|
@@ -378,4 +378,4 @@ interface Effect {
|
|
|
378
378
|
}
|
|
379
379
|
//#endregion
|
|
380
380
|
export { ProxySignal as i, Region as n, Computed as r, Effect as t };
|
|
381
|
-
//# sourceMappingURL=Effect-
|
|
381
|
+
//# sourceMappingURL=Effect-Dewn7MLc.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Effect-
|
|
1
|
+
{"version":3,"file":"Effect-Dewn7MLc.d.cts","names":[],"sources":["../src/types/constants.ts","../src/types/ProxySignal.ts","../src/types/Subscription.ts","../src/types/Computed.ts","../src/types/ErrorBoundary.ts","../src/types/Region.ts","../src/types/Effect.ts"],"mappings":";;;;;cAGa;;;;cAKA;;;;cAKA;;;;;;;UCNY;;;;EAIxB,aAAa;;;;EAKb,aAAa;;;;EAKb,oBAAoB;;;;EAKpB;;;;;;;;UClBwB;;;;EAIxB,QAAQ,cAAc;;;;EAKtB,QAAQ,WAAW;;;;;EAMnB,YAAY;;;;;EAMZ,YAAY;;;;;;;EAQZ,gBAAgB;;;;;;EAOhB;;;;;EAMA;;;;EAKA;;;;;;;;;UC/CwB,SAAS;;;;EAIjC,aAAa;;;;;;;;EASb;;;;EAKA,OAAO;;;;EAKP,WAAW;;;;EAKX,aAAa;;;;EAKb,aAAa;;;;;;;EAQb;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;EAQA;;;;;;;EAQA;;;;;;;;;EAUA;;;;;;;;;;;;;;;EAgBA;;;;;;;;;;;;;EAcA;;;;EAKA,UAAU;;;;EAKV;;;;;;;;;;UC3HwB;;;;;;EAMxB;;;;;EAMA;;;;;EAMA,QAAQ;;;;;;;;;EAUR,cAAc,cAAc;;;;UCnCJ;EACxB,WAAW;EACX,SAAS;EAET,gBAAgB;EAChB,YAAY;EACZ;;;;;EAMA,YAAY,IAAI;;;;EAKhB;;;;EAKA,SAAS;;;;;;;EAQT,gBAAgB;;;;;;;EAQhB;;;;;;EAOA;;;;;;;UCtCwB;;;;EAIxB,aAAa;;;;;EAMb,WAAW;;;;EAKX,SAAS;;;;EAKT,aAAa;EAKb,YAAY;;;;EAKZ;;;;;;EAOA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;EAWA,iBAAiB,IAAI;;;;EAKrB;;;;;;EAOA,SAAS;;;;;;EAOT,gBAAgB,cAAc;;;;;;;;;EAU9B;;;;;;;;;;;;;;;;EAiBA"}
|
package/dist/compile.cjs
CHANGED
|
@@ -2800,7 +2800,7 @@ function buildServerComponentNode(node, status, b) {
|
|
|
2800
2800
|
const nameAttribute = slot.attributes.find((a) => a.name === "name");
|
|
2801
2801
|
const slotName = nameAttribute?.value ? trimQuotes(nameAttribute.value) : "_";
|
|
2802
2802
|
const slotParams = [slot.hasSlotProps ? "$slot: Record<PropertyKey, any>" : "_$slot?: Record<PropertyKey, any>", "// @ts-ignore\n// eslint-disable-next-line no-unused-vars\n$context?: Record<PropertyKey, any>"];
|
|
2803
|
-
b.append(`${slot.hasSlotProps ? "// @ts-ignore\n" : ""}${slotsName}["${slotName}"] = (\n${slotParams.join(",\n")}\n) => {`);
|
|
2803
|
+
b.append(`${slot.hasSlotProps ? "// @ts-ignore\n" : ""}${slotsName}["${slotName}"] = async (\n${slotParams.join(",\n")}\n) => {`);
|
|
2804
2804
|
b.append(`let t_body = "";`);
|
|
2805
2805
|
for (let child of slot.children) buildServerNode(child, status, b);
|
|
2806
2806
|
if (status.output) {
|
|
@@ -2819,7 +2819,7 @@ function buildServerComponentNode(node, status, b) {
|
|
|
2819
2819
|
let renderParams = `${propsName}, $context`;
|
|
2820
2820
|
if (slotsName !== "undefined") renderParams += `, ${slotsName}`;
|
|
2821
2821
|
const componentResult = nextVarName("comp", status);
|
|
2822
|
-
b.append(`const ${componentResult} = ${componentName}(${renderParams});`);
|
|
2822
|
+
b.append(`const ${componentResult} = await ${componentName}(${renderParams});`);
|
|
2823
2823
|
b.append(`${status.inHead ? "t_head" : "t_body"} += ${componentResult}.body;`);
|
|
2824
2824
|
b.append(`t_head += ${componentResult}.head;`);
|
|
2825
2825
|
status.output += HYDRATION_END_COMMENT;
|
|
@@ -2827,16 +2827,37 @@ function buildServerComponentNode(node, status, b) {
|
|
|
2827
2827
|
}
|
|
2828
2828
|
//#endregion
|
|
2829
2829
|
//#region src/compile/build/server/buildServerAwaitNode.ts
|
|
2830
|
+
/**
|
|
2831
|
+
* Builds an `@await` boundary for the server (ASYNC.md → "Server rendering").
|
|
2832
|
+
*
|
|
2833
|
+
* Rather than inlining the `with` branch (the old shape), the boundary is
|
|
2834
|
+
* handed to the `t_await_server` runtime helper: content and `with` branches
|
|
2835
|
+
* become closures, and the helper decides at render time whether resolved
|
|
2836
|
+
* content can ship (all `source: "server"` reads settled) or the `with`
|
|
2837
|
+
* branch + client fetch is the honest output. The runtime emits the
|
|
2838
|
+
* hydration markers and anchor itself, including the `<!--t-await:...-->`
|
|
2839
|
+
* values payload for resolved boundaries.
|
|
2840
|
+
*/
|
|
2830
2841
|
function buildServerAwaitNode(node, status, b) {
|
|
2831
|
-
status.output += HYDRATION_START_COMMENT;
|
|
2832
2842
|
flushOutput(status, b);
|
|
2833
|
-
|
|
2834
|
-
status.
|
|
2835
|
-
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
|
|
2843
|
+
status.imports.add("t_await_server");
|
|
2844
|
+
const id = status.awaitCount++;
|
|
2845
|
+
const resultName = nextVarName("await", status);
|
|
2846
|
+
b.append(`const ${resultName} = await t_await_server("${id}", async () => {`);
|
|
2847
|
+
b.append(`let t_body = "";`);
|
|
2848
|
+
b.append(`let t_head = "";`);
|
|
2849
|
+
for (let branch of node.children) if (isControlNode(branch) && branch.operation === "@await") for (let child of branch.children) buildServerNode(child, status, b);
|
|
2839
2850
|
flushOutput(status, b);
|
|
2851
|
+
b.append(`return { body: t_body, head: t_head };`);
|
|
2852
|
+
b.append(`}, async () => {`);
|
|
2853
|
+
b.append(`let t_body = "";`);
|
|
2854
|
+
b.append(`let t_head = "";`);
|
|
2855
|
+
for (let branch of node.children) if (isControlNode(branch) && branch.operation === "@with") for (let child of branch.children) buildServerNode(child, status, b);
|
|
2856
|
+
flushOutput(status, b);
|
|
2857
|
+
b.append(`return { body: t_body, head: t_head };`);
|
|
2858
|
+
b.append(`});`);
|
|
2859
|
+
b.append(`${status.inHead ? "t_head" : "t_body"} += ${resultName}.body;`);
|
|
2860
|
+
b.append(`t_head += ${resultName}.head;`);
|
|
2840
2861
|
}
|
|
2841
2862
|
//#endregion
|
|
2842
2863
|
//#region src/compile/build/server/buildServerForNode.ts
|
|
@@ -3091,7 +3112,7 @@ function buildServerSlotNode(node, status, b) {
|
|
|
3091
3112
|
else b.append(`${propsName}["${name}"] = true;`);
|
|
3092
3113
|
}
|
|
3093
3114
|
b.append(`if ($slots && $slots["${slotName}"]) {`);
|
|
3094
|
-
b.append(`${status.inHead ? "t_head" : "t_body"} += $slots["${slotName}"](${slotHasProps ? propsName : "undefined"}, $context);`);
|
|
3115
|
+
b.append(`${status.inHead ? "t_head" : "t_body"} += await $slots["${slotName}"](${slotHasProps ? propsName : "undefined"}, $context);`);
|
|
3095
3116
|
const fill = node.children.find((c) => isSpecialNode(c) && (c.tagName === "fill" || c.tagName === "filldef"));
|
|
3096
3117
|
if (fill && isSpecialNode(fill) && fill.children.length) {
|
|
3097
3118
|
b.append(`} else {`);
|
|
@@ -3194,6 +3215,8 @@ const importsMap = {
|
|
|
3194
3215
|
$unwrap: "import { $unwrap } from \"${folder}\";",
|
|
3195
3216
|
$peek: "import { $peek } from \"${folder}\";",
|
|
3196
3217
|
$batch: "import { $batch } from \"${folder}\";",
|
|
3218
|
+
t_server_flush: "import { t_server_flush } from \"${folder}\";",
|
|
3219
|
+
t_await_server: "import { t_await_server } from \"${folder}\";",
|
|
3197
3220
|
t_fmt: "import { t_fmt } from \"${folder}\";",
|
|
3198
3221
|
t_attr: "import { t_attr } from \"${folder}\";",
|
|
3199
3222
|
t_class: "import { t_class } from \"${folder}\";",
|
|
@@ -3236,18 +3259,24 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3236
3259
|
if (/\$unwrap\b/.test(scriptCode)) imports.add("$unwrap");
|
|
3237
3260
|
if (/\$peek\b/.test(scriptCode)) imports.add("$peek");
|
|
3238
3261
|
if (/\$batch\b/.test(scriptCode)) imports.add("$batch");
|
|
3262
|
+
const asyncChunks = /* @__PURE__ */ new Set();
|
|
3263
|
+
for (let [i, chunk] of template.script.entries()) if (chunk.script === "/* @params */" && i > 0) asyncChunks.add(i - 1);
|
|
3239
3264
|
let currentIndex = 0;
|
|
3240
3265
|
let current = template.components[0];
|
|
3241
|
-
for (let chunk of template.script) if (chunk.script === "/* @params */") {
|
|
3266
|
+
for (let [chunkIndex, chunk] of template.script.entries()) if (chunk.script === "/* @params */") {
|
|
3242
3267
|
let params = [
|
|
3243
3268
|
current.params ?? `${current.props?.length ? "$props: Record<PropertyKey, any>" : "_$props?: Record<PropertyKey, any>"}`,
|
|
3244
3269
|
`${current.contextProps?.length || current.markup && markupRendersComponent(current.markup) || current.error && markupRendersComponent(current.error) ? "$context" : "_$context"}?: Record<PropertyKey, any>`,
|
|
3245
3270
|
`${current.slotProps?.length ? "$slots" : "_$slots"}?: Record<string, ServerSlotRender>`
|
|
3246
3271
|
];
|
|
3247
3272
|
b.append(params.join(",\n") + ",");
|
|
3248
|
-
} else if (chunk.script === ") /* @return_type */ {") b.append("): { body: string; head: string } {");
|
|
3273
|
+
} else if (chunk.script === ") /* @return_type */ {") b.append("): Promise<{ body: string; head: string }> {");
|
|
3249
3274
|
else if (chunk.script === "/* @start */") {
|
|
3250
3275
|
if (current.contextProps?.length) b.append(`$context = Object.assign({}, $context);`);
|
|
3276
|
+
if (containsAwaitGroup(current.markup) || containsAwaitGroup(current.error) || containsAwaitGroup(current.head)) {
|
|
3277
|
+
imports.add("t_server_flush");
|
|
3278
|
+
b.append(`return t_server_flush(async () => {`);
|
|
3279
|
+
}
|
|
3251
3280
|
b.append(`let t_body = "";`);
|
|
3252
3281
|
b.append(`let t_head = "";`);
|
|
3253
3282
|
} else if (chunk.script === "/* @render */") {
|
|
@@ -3258,6 +3287,7 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3258
3287
|
styleHash: current.style?.hash || "",
|
|
3259
3288
|
varNames: {},
|
|
3260
3289
|
preserveWhitespace: false,
|
|
3290
|
+
awaitCount: 0,
|
|
3261
3291
|
options
|
|
3262
3292
|
};
|
|
3263
3293
|
b.append("");
|
|
@@ -3281,6 +3311,7 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3281
3311
|
styleHash: current.style?.hash || "",
|
|
3282
3312
|
varNames: {},
|
|
3283
3313
|
preserveWhitespace: false,
|
|
3314
|
+
awaitCount: 0,
|
|
3284
3315
|
options
|
|
3285
3316
|
};
|
|
3286
3317
|
b.append(`} catch (${current.errorVar}) {`);
|
|
@@ -3303,6 +3334,7 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3303
3334
|
varNames: {},
|
|
3304
3335
|
preserveWhitespace: false,
|
|
3305
3336
|
inHead: true,
|
|
3337
|
+
awaitCount: 0,
|
|
3306
3338
|
options
|
|
3307
3339
|
};
|
|
3308
3340
|
b.append("");
|
|
@@ -3319,9 +3351,23 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3319
3351
|
}
|
|
3320
3352
|
} else if (chunk.script === "/* @end */") {
|
|
3321
3353
|
b.append(`return { body: t_body, head: t_head };`);
|
|
3354
|
+
if (containsAwaitGroup(current.markup) || containsAwaitGroup(current.error) || containsAwaitGroup(current.head)) b.append(`});`);
|
|
3322
3355
|
currentIndex += 1;
|
|
3323
3356
|
current = template.components[currentIndex];
|
|
3324
|
-
} else b.append(chunk.script);
|
|
3357
|
+
} else if (asyncChunks.has(chunkIndex)) b.append(chunk.script.replace(/(?<!async\s)function\s+([A-Za-z_$][\w$]*)((?:<(?:[^<>]|<[^<>]*>)*>)?)\s*\($/, "async function $1$2("));
|
|
3358
|
+
else b.append(chunk.script);
|
|
3359
|
+
}
|
|
3360
|
+
/**
|
|
3361
|
+
* Whether a markup tree contains an `@await` boundary, so the component's
|
|
3362
|
+
* render must be wrapped in a flush.
|
|
3363
|
+
*/
|
|
3364
|
+
function containsAwaitGroup(node) {
|
|
3365
|
+
if (node === void 0 || node === null) return false;
|
|
3366
|
+
if (isControlNode(node) && node.operation === "@await group") return true;
|
|
3367
|
+
if (node.type !== "text" && node.type !== "comment") {
|
|
3368
|
+
for (let child of node.children) if (containsAwaitGroup(child)) return true;
|
|
3369
|
+
}
|
|
3370
|
+
return false;
|
|
3325
3371
|
}
|
|
3326
3372
|
//#endregion
|
|
3327
3373
|
//#region src/compile/utils/trimWhitespace.ts
|
package/dist/compile.mjs
CHANGED
|
@@ -2799,7 +2799,7 @@ function buildServerComponentNode(node, status, b) {
|
|
|
2799
2799
|
const nameAttribute = slot.attributes.find((a) => a.name === "name");
|
|
2800
2800
|
const slotName = nameAttribute?.value ? trimQuotes(nameAttribute.value) : "_";
|
|
2801
2801
|
const slotParams = [slot.hasSlotProps ? "$slot: Record<PropertyKey, any>" : "_$slot?: Record<PropertyKey, any>", "// @ts-ignore\n// eslint-disable-next-line no-unused-vars\n$context?: Record<PropertyKey, any>"];
|
|
2802
|
-
b.append(`${slot.hasSlotProps ? "// @ts-ignore\n" : ""}${slotsName}["${slotName}"] = (\n${slotParams.join(",\n")}\n) => {`);
|
|
2802
|
+
b.append(`${slot.hasSlotProps ? "// @ts-ignore\n" : ""}${slotsName}["${slotName}"] = async (\n${slotParams.join(",\n")}\n) => {`);
|
|
2803
2803
|
b.append(`let t_body = "";`);
|
|
2804
2804
|
for (let child of slot.children) buildServerNode(child, status, b);
|
|
2805
2805
|
if (status.output) {
|
|
@@ -2818,7 +2818,7 @@ function buildServerComponentNode(node, status, b) {
|
|
|
2818
2818
|
let renderParams = `${propsName}, $context`;
|
|
2819
2819
|
if (slotsName !== "undefined") renderParams += `, ${slotsName}`;
|
|
2820
2820
|
const componentResult = nextVarName("comp", status);
|
|
2821
|
-
b.append(`const ${componentResult} = ${componentName}(${renderParams});`);
|
|
2821
|
+
b.append(`const ${componentResult} = await ${componentName}(${renderParams});`);
|
|
2822
2822
|
b.append(`${status.inHead ? "t_head" : "t_body"} += ${componentResult}.body;`);
|
|
2823
2823
|
b.append(`t_head += ${componentResult}.head;`);
|
|
2824
2824
|
status.output += HYDRATION_END_COMMENT;
|
|
@@ -2826,16 +2826,37 @@ function buildServerComponentNode(node, status, b) {
|
|
|
2826
2826
|
}
|
|
2827
2827
|
//#endregion
|
|
2828
2828
|
//#region src/compile/build/server/buildServerAwaitNode.ts
|
|
2829
|
+
/**
|
|
2830
|
+
* Builds an `@await` boundary for the server (ASYNC.md → "Server rendering").
|
|
2831
|
+
*
|
|
2832
|
+
* Rather than inlining the `with` branch (the old shape), the boundary is
|
|
2833
|
+
* handed to the `t_await_server` runtime helper: content and `with` branches
|
|
2834
|
+
* become closures, and the helper decides at render time whether resolved
|
|
2835
|
+
* content can ship (all `source: "server"` reads settled) or the `with`
|
|
2836
|
+
* branch + client fetch is the honest output. The runtime emits the
|
|
2837
|
+
* hydration markers and anchor itself, including the `<!--t-await:...-->`
|
|
2838
|
+
* values payload for resolved boundaries.
|
|
2839
|
+
*/
|
|
2829
2840
|
function buildServerAwaitNode(node, status, b) {
|
|
2830
|
-
status.output += HYDRATION_START_COMMENT;
|
|
2831
2841
|
flushOutput(status, b);
|
|
2832
|
-
|
|
2833
|
-
status.
|
|
2834
|
-
|
|
2835
|
-
}
|
|
2836
|
-
|
|
2837
|
-
|
|
2842
|
+
status.imports.add("t_await_server");
|
|
2843
|
+
const id = status.awaitCount++;
|
|
2844
|
+
const resultName = nextVarName("await", status);
|
|
2845
|
+
b.append(`const ${resultName} = await t_await_server("${id}", async () => {`);
|
|
2846
|
+
b.append(`let t_body = "";`);
|
|
2847
|
+
b.append(`let t_head = "";`);
|
|
2848
|
+
for (let branch of node.children) if (isControlNode(branch) && branch.operation === "@await") for (let child of branch.children) buildServerNode(child, status, b);
|
|
2838
2849
|
flushOutput(status, b);
|
|
2850
|
+
b.append(`return { body: t_body, head: t_head };`);
|
|
2851
|
+
b.append(`}, async () => {`);
|
|
2852
|
+
b.append(`let t_body = "";`);
|
|
2853
|
+
b.append(`let t_head = "";`);
|
|
2854
|
+
for (let branch of node.children) if (isControlNode(branch) && branch.operation === "@with") for (let child of branch.children) buildServerNode(child, status, b);
|
|
2855
|
+
flushOutput(status, b);
|
|
2856
|
+
b.append(`return { body: t_body, head: t_head };`);
|
|
2857
|
+
b.append(`});`);
|
|
2858
|
+
b.append(`${status.inHead ? "t_head" : "t_body"} += ${resultName}.body;`);
|
|
2859
|
+
b.append(`t_head += ${resultName}.head;`);
|
|
2839
2860
|
}
|
|
2840
2861
|
//#endregion
|
|
2841
2862
|
//#region src/compile/build/server/buildServerForNode.ts
|
|
@@ -3090,7 +3111,7 @@ function buildServerSlotNode(node, status, b) {
|
|
|
3090
3111
|
else b.append(`${propsName}["${name}"] = true;`);
|
|
3091
3112
|
}
|
|
3092
3113
|
b.append(`if ($slots && $slots["${slotName}"]) {`);
|
|
3093
|
-
b.append(`${status.inHead ? "t_head" : "t_body"} += $slots["${slotName}"](${slotHasProps ? propsName : "undefined"}, $context);`);
|
|
3114
|
+
b.append(`${status.inHead ? "t_head" : "t_body"} += await $slots["${slotName}"](${slotHasProps ? propsName : "undefined"}, $context);`);
|
|
3094
3115
|
const fill = node.children.find((c) => isSpecialNode(c) && (c.tagName === "fill" || c.tagName === "filldef"));
|
|
3095
3116
|
if (fill && isSpecialNode(fill) && fill.children.length) {
|
|
3096
3117
|
b.append(`} else {`);
|
|
@@ -3193,6 +3214,8 @@ const importsMap = {
|
|
|
3193
3214
|
$unwrap: "import { $unwrap } from \"${folder}\";",
|
|
3194
3215
|
$peek: "import { $peek } from \"${folder}\";",
|
|
3195
3216
|
$batch: "import { $batch } from \"${folder}\";",
|
|
3217
|
+
t_server_flush: "import { t_server_flush } from \"${folder}\";",
|
|
3218
|
+
t_await_server: "import { t_await_server } from \"${folder}\";",
|
|
3196
3219
|
t_fmt: "import { t_fmt } from \"${folder}\";",
|
|
3197
3220
|
t_attr: "import { t_attr } from \"${folder}\";",
|
|
3198
3221
|
t_class: "import { t_class } from \"${folder}\";",
|
|
@@ -3235,18 +3258,24 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3235
3258
|
if (/\$unwrap\b/.test(scriptCode)) imports.add("$unwrap");
|
|
3236
3259
|
if (/\$peek\b/.test(scriptCode)) imports.add("$peek");
|
|
3237
3260
|
if (/\$batch\b/.test(scriptCode)) imports.add("$batch");
|
|
3261
|
+
const asyncChunks = /* @__PURE__ */ new Set();
|
|
3262
|
+
for (let [i, chunk] of template.script.entries()) if (chunk.script === "/* @params */" && i > 0) asyncChunks.add(i - 1);
|
|
3238
3263
|
let currentIndex = 0;
|
|
3239
3264
|
let current = template.components[0];
|
|
3240
|
-
for (let chunk of template.script) if (chunk.script === "/* @params */") {
|
|
3265
|
+
for (let [chunkIndex, chunk] of template.script.entries()) if (chunk.script === "/* @params */") {
|
|
3241
3266
|
let params = [
|
|
3242
3267
|
current.params ?? `${current.props?.length ? "$props: Record<PropertyKey, any>" : "_$props?: Record<PropertyKey, any>"}`,
|
|
3243
3268
|
`${current.contextProps?.length || current.markup && markupRendersComponent(current.markup) || current.error && markupRendersComponent(current.error) ? "$context" : "_$context"}?: Record<PropertyKey, any>`,
|
|
3244
3269
|
`${current.slotProps?.length ? "$slots" : "_$slots"}?: Record<string, ServerSlotRender>`
|
|
3245
3270
|
];
|
|
3246
3271
|
b.append(params.join(",\n") + ",");
|
|
3247
|
-
} else if (chunk.script === ") /* @return_type */ {") b.append("): { body: string; head: string } {");
|
|
3272
|
+
} else if (chunk.script === ") /* @return_type */ {") b.append("): Promise<{ body: string; head: string }> {");
|
|
3248
3273
|
else if (chunk.script === "/* @start */") {
|
|
3249
3274
|
if (current.contextProps?.length) b.append(`$context = Object.assign({}, $context);`);
|
|
3275
|
+
if (containsAwaitGroup(current.markup) || containsAwaitGroup(current.error) || containsAwaitGroup(current.head)) {
|
|
3276
|
+
imports.add("t_server_flush");
|
|
3277
|
+
b.append(`return t_server_flush(async () => {`);
|
|
3278
|
+
}
|
|
3250
3279
|
b.append(`let t_body = "";`);
|
|
3251
3280
|
b.append(`let t_head = "";`);
|
|
3252
3281
|
} else if (chunk.script === "/* @render */") {
|
|
@@ -3257,6 +3286,7 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3257
3286
|
styleHash: current.style?.hash || "",
|
|
3258
3287
|
varNames: {},
|
|
3259
3288
|
preserveWhitespace: false,
|
|
3289
|
+
awaitCount: 0,
|
|
3260
3290
|
options
|
|
3261
3291
|
};
|
|
3262
3292
|
b.append("");
|
|
@@ -3280,6 +3310,7 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3280
3310
|
styleHash: current.style?.hash || "",
|
|
3281
3311
|
varNames: {},
|
|
3282
3312
|
preserveWhitespace: false,
|
|
3313
|
+
awaitCount: 0,
|
|
3283
3314
|
options
|
|
3284
3315
|
};
|
|
3285
3316
|
b.append(`} catch (${current.errorVar}) {`);
|
|
@@ -3302,6 +3333,7 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3302
3333
|
varNames: {},
|
|
3303
3334
|
preserveWhitespace: false,
|
|
3304
3335
|
inHead: true,
|
|
3336
|
+
awaitCount: 0,
|
|
3305
3337
|
options
|
|
3306
3338
|
};
|
|
3307
3339
|
b.append("");
|
|
@@ -3318,9 +3350,23 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3318
3350
|
}
|
|
3319
3351
|
} else if (chunk.script === "/* @end */") {
|
|
3320
3352
|
b.append(`return { body: t_body, head: t_head };`);
|
|
3353
|
+
if (containsAwaitGroup(current.markup) || containsAwaitGroup(current.error) || containsAwaitGroup(current.head)) b.append(`});`);
|
|
3321
3354
|
currentIndex += 1;
|
|
3322
3355
|
current = template.components[currentIndex];
|
|
3323
|
-
} else b.append(chunk.script);
|
|
3356
|
+
} else if (asyncChunks.has(chunkIndex)) b.append(chunk.script.replace(/(?<!async\s)function\s+([A-Za-z_$][\w$]*)((?:<(?:[^<>]|<[^<>]*>)*>)?)\s*\($/, "async function $1$2("));
|
|
3357
|
+
else b.append(chunk.script);
|
|
3358
|
+
}
|
|
3359
|
+
/**
|
|
3360
|
+
* Whether a markup tree contains an `@await` boundary, so the component's
|
|
3361
|
+
* render must be wrapped in a flush.
|
|
3362
|
+
*/
|
|
3363
|
+
function containsAwaitGroup(node) {
|
|
3364
|
+
if (node === void 0 || node === null) return false;
|
|
3365
|
+
if (isControlNode(node) && node.operation === "@await group") return true;
|
|
3366
|
+
if (node.type !== "text" && node.type !== "comment") {
|
|
3367
|
+
for (let child of node.children) if (containsAwaitGroup(child)) return true;
|
|
3368
|
+
}
|
|
3369
|
+
return false;
|
|
3324
3370
|
}
|
|
3325
3371
|
//#endregion
|
|
3326
3372
|
//#region src/compile/utils/trimWhitespace.ts
|