| ... | ... | @@ -0,0 +1,107 @@ |
| 1 | import * as ssr from "./ssr.ts";
|
| 2 | // @ts-ignore no types :(
|
| 3 | import * as marko from "marko/debug/html";
|
| 4 | // @ts-ignore no types :(
|
| 5 | export * from "marko/debug/html";
|
| 6 |
|
| 7 | export const createTemplate = (templateId: string, renderer) => {
|
| 8 | const { render } = marko.createTemplate(templateId, renderer);
|
| 9 | function wrap(props: Record<string, unknown>, n: number) {
|
| 10 | // Marko components
|
| 11 | const cloverAsyncMarker = { isAsync: false };
|
| 12 | let r: ssr.Render | undefined = undefined;
|
| 13 | try {
|
| 14 | r = ssr.getCurrentRender();
|
| 15 | } catch {}
|
| 16 | // Support using Marko outside of Clover SSR
|
| 17 | if (r) {
|
| 18 | const markoResult = render.call(renderer, {
|
| 19 | ...props,
|
| 20 | $global: { clover: r, cloverAsyncMarker },
|
| 21 | });
|
| 22 | if (cloverAsyncMarker.isAsync) {
|
| 23 | return markoResult.then(ssr.html);
|
| 24 | }
|
| 25 | const rr = markoResult.toString();
|
| 26 | return ssr.html(rr);
|
| 27 | } else {
|
| 28 | return renderer(props, n);
|
| 29 | }
|
| 30 | }
|
| 31 | wrap.render = render;
|
| 32 | wrap.unwrapped = renderer;
|
| 33 | return wrap;
|
| 34 | };
|
| 35 |
|
| 36 | export const dynamicTag = (
|
| 37 | scopeId,
|
| 38 | accessor,
|
| 39 | tag,
|
| 40 | inputOrArgs,
|
| 41 | content,
|
| 42 | inputIsArgs,
|
| 43 | serializeReason,
|
| 44 | ) => {
|
| 45 | if (typeof tag === "function") {
|
| 46 | clover: {
|
| 47 | const unwrapped = tag.unwrapped;
|
| 48 | if (unwrapped) {
|
| 49 | tag = unwrapped;
|
| 50 | break clover;
|
| 51 | }
|
| 52 | let r: ssr.Render;
|
| 53 | try {
|
| 54 | r = ssr.getCurrentRender();
|
| 55 | if (!r) throw 0;
|
| 56 | } catch {
|
| 57 | r = marko.$global().clover as ssr.Render;
|
| 58 | }
|
| 59 | if (!r) throw new Error("No Clover Render Active");
|
| 60 | const subRender = ssr.initRender(r.async !== -1, r.user);
|
| 61 | const resolved = ssr.resolveNode(subRender, [
|
| 62 | ssr.kElement,
|
| 63 | tag,
|
| 64 | inputOrArgs,
|
| 65 | ]);
|
| 66 |
|
| 67 | if (subRender.async > 0) {
|
| 68 | const marker = marko.$global().cloverAsyncMarker;
|
| 69 | marker.isAsync = true;
|
| 70 |
|
| 71 | // Wait for async work to finish
|
| 72 | const { resolve, reject, promise } = Promise.withResolvers<string>();
|
| 73 | subRender.asyncDone = () => {
|
| 74 | const rejections = subRender.rejections;
|
| 75 | if (!rejections) return resolve(ssr.renderNodeOrUndefined(resolved));
|
| 76 | (r.rejections ??= []).push(...rejections);
|
| 77 | return reject(new Error("Render had errors"));
|
| 78 | };
|
| 79 | marko.fork(
|
| 80 | scopeId,
|
| 81 | accessor,
|
| 82 | promise,
|
| 83 | (string: string) => marko.write(string),
|
| 84 | 0,
|
| 85 | );
|
| 86 | } else {
|
| 87 | marko.write(ssr.renderNodeOrUndefined(resolved));
|
| 88 | }
|
| 89 | return;
|
| 90 | }
|
| 91 | }
|
| 92 | return marko.dynamicTag(
|
| 93 | scopeId,
|
| 94 | accessor,
|
| 95 | tag,
|
| 96 | inputOrArgs,
|
| 97 | content,
|
| 98 | inputIsArgs,
|
| 99 | serializeReason,
|
| 100 | );
|
| 101 | };
|
| 102 |
|
| 103 | export function fork(scopeId, accessor, promise, callback, serializeMarker) {
|
| 104 | const marker = marko.$global().cloverAsyncMarker;
|
| 105 | marker.isAsync = true;
|
| 106 | marko.fork(scopeId, accessor, promise, callback, serializeMarker);
|
| 107 | }
|