diff --git a/packages/dom-expressions/package.json b/packages/dom-expressions/package.json index a3329218..ac14e18e 100644 --- a/packages/dom-expressions/package.json +++ b/packages/dom-expressions/package.json @@ -20,11 +20,11 @@ }, "peerDependencies": { "csstype": "^3.0", - "seroval": "^0.7.0" + "seroval": "^0.10.1" }, "devDependencies": { "babel-plugin-jsx-dom-expressions": "^0.36.10", "csstype": "^3.1", - "seroval": "^0.7.0" + "seroval": "^0.10.1" } } diff --git a/packages/dom-expressions/src/serializer.d.ts b/packages/dom-expressions/src/serializer.d.ts index fef2f9e5..02a1d706 100644 --- a/packages/dom-expressions/src/serializer.d.ts +++ b/packages/dom-expressions/src/serializer.d.ts @@ -1 +1,3 @@ -export default function stringify(root: unknown): string; \ No newline at end of file +import { Serializer } from "seroval"; + +export default function createSerializer(onData: (value: string) => void): Serializer; \ No newline at end of file diff --git a/packages/dom-expressions/src/serializer.js b/packages/dom-expressions/src/serializer.js index 2fb92822..a407a953 100644 --- a/packages/dom-expressions/src/serializer.js +++ b/packages/dom-expressions/src/serializer.js @@ -1,10 +1,21 @@ -import { serialize, Feature } from "seroval" +import { Feature, Serializer, CROSS_REFERENCE_HEADER } from "seroval" const ES2017FLAG = Feature.AggregateError // ES2021 | Feature.BigInt // ES2020 | Feature.BigIntTypedArray // ES2020; -export default function stringify(data) { - return serialize(data, { disabledFeatures: ES2017FLAG }); -} \ No newline at end of file +const GLOBAL_IDENTIFIER = '$HY.r'; // TODO this is a pending name + +export default function createSerializer(onData) { + return new Serializer({ + globalIdentifier: GLOBAL_IDENTIFIER, + disabledFeatures: ES2017FLAG, + onData, + }); +} + +// TODO +export function getHeaderScript() { + return CROSS_REFERENCE_HEADER; +} diff --git a/packages/dom-expressions/src/server.js b/packages/dom-expressions/src/server.js index 8a210c88..e2b92126 100644 --- a/packages/dom-expressions/src/server.js +++ b/packages/dom-expressions/src/server.js @@ -1,7 +1,7 @@ import { Aliases, BooleanAttributes, ChildProperties } from "./constants"; import { sharedConfig, root } from "rxcore"; -import stringify from "./serializer"; -export { stringify }; +import createSerializer from "./serializer"; +export { createSerializer }; export { createComponent } from "rxcore"; // Based on https://github.com/WebReflection/domtagger/blob/master/esm/sanitizer.js @@ -11,6 +11,7 @@ const REPLACE_SCRIPT = `function $df(e,n,t,o,d){if(t=document.getElementById(e), export function renderToString(code, options = {}) { let scripts = ""; + const serializer = createSerializer((script) => scripts += script); sharedConfig.context = { id: options.renderId || "", count: 0, @@ -18,10 +19,8 @@ export function renderToString(code, options = {}) { lazy: {}, assets: [], nonce: options.nonce, - writeResource(id, p, error) { - if (sharedConfig.context.noHydrate) return; - if (error) return (scripts += `_$HY.set("${id}", ${stringify(p)});`); - scripts += `_$HY.set("${id}", ${stringify(p)});`; + writeResource(id, p) { + !sharedConfig.context.noHydrate && serializer.write(id, p); } }; let html = root(d => { @@ -31,6 +30,7 @@ export function renderToString(code, options = {}) { sharedConfig.context.noHydrate = true; html = injectAssets(sharedConfig.context.assets, html); if (scripts.length) html = injectScripts(html, scripts, options.nonce); + serializer.close(); return html; } @@ -50,6 +50,9 @@ export function renderToStream(code, options = {}) { let { nonce, onCompleteShell, onCompleteAll, renderId } = options; let dispose; const blockingResources = []; + const serializer = createSerializer((value) => { + // TODO + }); const registry = new Map(); const dedupe = new WeakMap(); const checkEnd = () => { @@ -118,18 +121,21 @@ export function renderToStream(code, options = {}) { ); }, writeResource(id, p, error, wait) { + // TODO this is a draft const serverOnly = sharedConfig.context.noHydrate; - if (error) return !serverOnly && pushTask(serializeSet(dedupe, id, p)); - if (!p || typeof p !== "object" || !("then" in p)) - return !serverOnly && pushTask(serializeSet(dedupe, id, p)); - if (!firstFlushed) wait && blockingResources.push(p); - else !serverOnly && pushTask(`_$HY.init("${id}")`); - if (serverOnly) return; - p.then(d => { - !completed && pushTask(serializeSet(dedupe, id, d)); - }).catch(() => { - !completed && pushTask(`_$HY.set("${id}", {})`); - }); + if (error) return !serverOnly && serializer.write(id, p); + if (!firstFlushed) { + if (wait) { + blockingResources.push(p); + !serverOnly && p.then((d) => { + serializer.write(id, d); + }).catch(() => { + serializer.write(id, {}); + }); + } + } else { + !serverOnly && serializer.write(p); + } }, registerFragment(key) { if (!registry.has(key)) { @@ -512,13 +518,6 @@ function waitForFragments(registry, key) { return false; } -function serializeSet(registry, key, value) { - const exist = registry.get(value); - if (exist) return `_$HY.set("${key}", _$HY.r["${exist}"][0])`; - value !== null && typeof value === "object" && registry.set(value, key); - return `_$HY.set("${key}", ${stringify(value)})`; -} - function replacePlaceholder(html, key, value) { const marker = `