@qwik.dev/core 2.0.0-beta.8 → 2.0.0-beta.9

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/server.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * @qwik.dev/core/server 2.0.0-beta.8-dev+434cd18
3
+ * @qwik.dev/core/server 2.0.0-beta.9-dev+6b582c7
4
4
  * Copyright QwikDev. All Rights Reserved.
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://github.com/QwikDev/qwik/blob/main/LICENSE
@@ -50,6 +50,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
50
50
  // packages/qwik/src/server/index.ts
51
51
  var index_exports = {};
52
52
  __export(index_exports, {
53
+ getQwikBackpatchExecutorScript: () => getQwikBackpatchExecutorScript,
53
54
  getQwikLoaderScript: () => getQwikLoaderScript,
54
55
  getQwikPrefetchWorkerScript: () => getQwikPrefetchWorkerScript,
55
56
  renderToStream: () => renderToStream,
@@ -334,6 +335,7 @@ var ELEMENT_KEY = "q:key";
334
335
  var ELEMENT_PROPS = "q:props";
335
336
  var ELEMENT_SEQ = "q:seq";
336
337
  var ELEMENT_SEQ_IDX = "q:seqIdx";
338
+ var ELEMENT_BACKPATCH_DATA = "qwik/backpatch";
337
339
  var NON_SERIALIZABLE_MARKER_PREFIX = ":";
338
340
  var USE_ON_LOCAL = NON_SERIALIZABLE_MARKER_PREFIX + "on";
339
341
  var USE_ON_LOCAL_SEQ_IDX = NON_SERIALIZABLE_MARKER_PREFIX + "onIdx";
@@ -1136,13 +1138,6 @@ function createPlatform(opts, resolvedManifest) {
1136
1138
  console.error("server can not rerender");
1137
1139
  return Promise.resolve();
1138
1140
  },
1139
- nextTick: (fn) => {
1140
- return new Promise((resolve) => {
1141
- setTimeout(() => {
1142
- resolve(fn());
1143
- });
1144
- });
1145
- },
1146
1141
  chunkForSymbol(symbolName, _chunk, parent) {
1147
1142
  return mapperFn(symbolName, mapper, parent);
1148
1143
  }
@@ -1187,7 +1182,7 @@ function getBuildBase(opts) {
1187
1182
  return `${globalThis.BASE_URL || "/"}build/`;
1188
1183
  }
1189
1184
  var versions = {
1190
- qwik: "2.0.0-beta.8-dev+434cd18",
1185
+ qwik: "2.0.0-beta.9-dev+6b582c7",
1191
1186
  qwikDom: "2.1.19"
1192
1187
  };
1193
1188
 
@@ -1198,6 +1193,41 @@ var import_build8 = require("@qwik.dev/core/build");
1198
1193
  // packages/qwik/src/server/scripts.ts
1199
1194
  var QWIK_LOADER_DEFAULT_MINIFIED = 'const t=document,e=window,n=new Set,o=new Set([t]);let r;const s=(t,e)=>Array.from(t.querySelectorAll(e)),a=t=>{const e=[];return o.forEach(n=>e.push(...s(n,t))),e},i=t=>{m(t),s(t,"[q\\\\:shadowroot]").forEach(t=>{const e=t.shadowRoot;e&&i(e)})},c=t=>t&&"function"==typeof t.then,l=(t,e,n=e.type)=>{a("[on"+t+"\\\\:"+n+"]").forEach(o=>{u(o,t,e,n)})},f=e=>{if(void 0===e._qwikjson_){let n=(e===t.documentElement?t.body:e).lastElementChild;for(;n;){if("SCRIPT"===n.tagName&&"qwik/json"===n.getAttribute("type")){e._qwikjson_=JSON.parse(n.textContent.replace(/\\\\x3C(\\/?script)/gi,"<$1"));break}n=n.previousElementSibling}}},p=(t,e)=>new CustomEvent(t,{detail:e}),u=async(e,n,o,r=o.type)=>{const s="on"+n+":"+r;e.hasAttribute("preventdefault:"+r)&&o.preventDefault(),e.hasAttribute("stoppropagation:"+r)&&o.stopPropagation();const a=e._qc_,i=a&&a.li.filter(t=>t[0]===s);if(i&&i.length>0){for(const t of i){const n=t[1].getFn([e,o],()=>e.isConnected)(o,e),r=o.cancelBubble;c(n)&&await n,r&&o.stopPropagation()}return}const l=e.getAttribute(s),p=e.qDispatchEvent;if(p)return p(o,n);if(l){const n=e.closest("[q\\\\:container]:not([q\\\\:container=html]):not([q\\\\:container=text])"),r=n.getAttribute("q:base"),s=n.getAttribute("q:version")||"unknown",a=n.getAttribute("q:manifest-hash")||"dev",i=new URL(r,t.baseURI);for(const p of l.split("\\n")){const l=new URL(p,i),u=l.href,q=l.hash.replace(/^#?([^?[|]*).*$/,"$1")||"default",h=performance.now();let _,d,y;const m=p.startsWith("#"),w={qBase:r,qManifest:a,qVersion:s,href:u,symbol:q,element:e,reqTime:h};if(m){const e=n.getAttribute("q:instance");_=(t["qFuncs_"+e]||[])[Number.parseInt(q)],_||(d="sync",y=Error("sym:"+q))}else{b("qsymbol",w);const t=l.href.split("#")[0];try{const e=import(t);f(n),_=(await e)[q],_||(d="no-symbol",y=Error(`${q} not in ${t}`))}catch(t){d||(d="async"),y=t}}if(!_){b("qerror",{importError:d,error:y,...w}),console.error(y);break}const g=t.__q_context__;if(e.isConnected)try{t.__q_context__=[e,o,l];const n=_(o,e);c(n)&&await n}catch(t){b("qerror",{error:t,...w})}finally{t.__q_context__=g}}}},b=(e,n)=>{t.dispatchEvent(p(e,n))},q=t=>t.replace(/([A-Z])/g,t=>"-"+t.toLowerCase()),h=async t=>{let e=q(t.type),n=t.target;for(l("-document",t,e);n&&n.getAttribute;){const o=u(n,"",t,e);let r=t.cancelBubble;c(o)&&await o,r||(r=r||t.cancelBubble||n.hasAttribute("stoppropagation:"+t.type)),n=t.bubbles&&!0!==r?n.parentElement:null}},_=t=>{l("-window",t,q(t.type))},d=()=>{var s;const c=t.readyState;if(!r&&("interactive"==c||"complete"==c)&&(o.forEach(i),r=1,b("qinit"),(null!=(s=e.requestIdleCallback)?s:e.setTimeout).bind(e)(()=>b("qidle")),n.has("qvisible"))){const t=a("[on\\\\:qvisible]"),e=new IntersectionObserver(t=>{for(const n of t)n.isIntersecting&&(e.unobserve(n.target),u(n.target,"",p("qvisible",n)))});t.forEach(t=>e.observe(t))}},y=(t,e,n,o=!1)=>{t.addEventListener(e,n,{capture:o,passive:!1})},m=(...t)=>{for(const r of t)"string"==typeof r?n.has(r)||(o.forEach(t=>y(t,r,h,!0)),y(e,r,_,!0),n.add(r)):o.has(r)||(n.forEach(t=>y(r,t,h,!0)),o.add(r))};if(!("__q_context__"in t)){t.__q_context__=0;const r=e.qwikevents;r&&(Array.isArray(r)?m(...r):m("click","input")),e.qwikevents={events:n,roots:o,push:m},y(t,"readystatechange",d),d()}';
1200
1195
  var QWIK_LOADER_DEFAULT_DEBUG = 'const doc = document;\nconst win = window;\nconst events = /* @__PURE__ */ new Set();\nconst roots = /* @__PURE__ */ new Set([doc]);\nlet hasInitialized;\nconst nativeQuerySelectorAll = (root, selector) => Array.from(root.querySelectorAll(selector));\nconst querySelectorAll = (query) => {\n const elements = [];\n roots.forEach((root) => elements.push(...nativeQuerySelectorAll(root, query)));\n return elements;\n};\nconst findShadowRoots = (fragment) => {\n processEventOrNode(fragment);\n nativeQuerySelectorAll(fragment, "[q\\\\:shadowroot]").forEach((parent) => {\n const shadowRoot = parent.shadowRoot;\n shadowRoot && findShadowRoots(shadowRoot);\n });\n};\nconst isPromise = (promise) => promise && typeof promise.then === "function";\nconst broadcast = (infix, ev, type = ev.type) => {\n querySelectorAll("[on" + infix + "\\\\:" + type + "]").forEach((el) => {\n dispatch(el, infix, ev, type);\n });\n};\nconst resolveContainer = (containerEl) => {\n if (containerEl._qwikjson_ === void 0) {\n const parentJSON = containerEl === doc.documentElement ? doc.body : containerEl;\n let script = parentJSON.lastElementChild;\n while (script) {\n if (script.tagName === "SCRIPT" && script.getAttribute("type") === "qwik/json") {\n containerEl._qwikjson_ = JSON.parse(\n script.textContent.replace(/\\\\x3C(\\/?script)/gi, "<$1")\n );\n break;\n }\n script = script.previousElementSibling;\n }\n }\n};\nconst createEvent = (eventName, detail) => new CustomEvent(eventName, {\n detail\n});\nconst dispatch = async (element, scope, ev, eventName = ev.type) => {\n const attrName = "on" + scope + ":" + eventName;\n if (element.hasAttribute("preventdefault:" + eventName)) {\n ev.preventDefault();\n }\n if (element.hasAttribute("stoppropagation:" + eventName)) {\n ev.stopPropagation();\n }\n const ctx = element._qc_;\n const relevantListeners = ctx && ctx.li.filter((li) => li[0] === attrName);\n if (relevantListeners && relevantListeners.length > 0) {\n for (const listener of relevantListeners) {\n const results = listener[1].getFn([element, ev], () => element.isConnected)(ev, element);\n const cancelBubble = ev.cancelBubble;\n if (isPromise(results)) {\n await results;\n }\n if (cancelBubble) {\n ev.stopPropagation();\n }\n }\n return;\n }\n const attrValue = element.getAttribute(attrName);\n const qDispatchEvent = element.qDispatchEvent;\n if (qDispatchEvent) {\n return qDispatchEvent(ev, scope);\n }\n if (attrValue) {\n const container = element.closest(\n "[q\\\\:container]:not([q\\\\:container=html]):not([q\\\\:container=text])"\n );\n const qBase = container.getAttribute("q:base");\n const qVersion = container.getAttribute("q:version") || "unknown";\n const qManifest = container.getAttribute("q:manifest-hash") || "dev";\n const base = new URL(qBase, doc.baseURI);\n for (const qrl of attrValue.split("\\n")) {\n const url = new URL(qrl, base);\n const href = url.href;\n const symbol = url.hash.replace(/^#?([^?[|]*).*$/, "$1") || "default";\n const reqTime = performance.now();\n let handler;\n let importError;\n let error;\n const isSync = qrl.startsWith("#");\n const eventData = {\n qBase,\n qManifest,\n qVersion,\n href,\n symbol,\n element,\n reqTime\n };\n if (isSync) {\n const hash = container.getAttribute("q:instance");\n handler = (doc["qFuncs_" + hash] || [])[Number.parseInt(symbol)];\n if (!handler) {\n importError = "sync";\n error = new Error("sym:" + symbol);\n }\n } else {\n emitEvent("qsymbol", eventData);\n const uri = url.href.split("#")[0];\n try {\n const module = import(\n uri\n );\n resolveContainer(container);\n handler = (await module)[symbol];\n if (!handler) {\n importError = "no-symbol";\n error = new Error(`${symbol} not in ${uri}`);\n }\n } catch (err) {\n importError || (importError = "async");\n error = err;\n }\n }\n if (!handler) {\n emitEvent("qerror", {\n importError,\n error,\n ...eventData\n });\n console.error(error);\n break;\n }\n const previousCtx = doc.__q_context__;\n if (element.isConnected) {\n try {\n doc.__q_context__ = [element, ev, url];\n const results = handler(ev, element);\n if (isPromise(results)) {\n await results;\n }\n } catch (error2) {\n emitEvent("qerror", { error: error2, ...eventData });\n } finally {\n doc.__q_context__ = previousCtx;\n }\n }\n }\n }\n};\nconst emitEvent = (eventName, detail) => {\n doc.dispatchEvent(createEvent(eventName, detail));\n};\nconst camelToKebab = (str) => str.replace(/([A-Z])/g, (a) => "-" + a.toLowerCase());\nconst processDocumentEvent = async (ev) => {\n let type = camelToKebab(ev.type);\n let element = ev.target;\n broadcast("-document", ev, type);\n while (element && element.getAttribute) {\n const results = dispatch(element, "", ev, type);\n let cancelBubble = ev.cancelBubble;\n if (isPromise(results)) {\n await results;\n }\n cancelBubble || (cancelBubble = cancelBubble || ev.cancelBubble || element.hasAttribute("stoppropagation:" + ev.type));\n element = ev.bubbles && cancelBubble !== true ? element.parentElement : null;\n }\n};\nconst processWindowEvent = (ev) => {\n broadcast("-window", ev, camelToKebab(ev.type));\n};\nconst processReadyStateChange = () => {\n var _a;\n const readyState = doc.readyState;\n if (!hasInitialized && (readyState == "interactive" || readyState == "complete")) {\n roots.forEach(findShadowRoots);\n hasInitialized = 1;\n emitEvent("qinit");\n const riC = (_a = win.requestIdleCallback) != null ? _a : win.setTimeout;\n riC.bind(win)(() => emitEvent("qidle"));\n if (events.has("qvisible")) {\n const results = querySelectorAll("[on\\\\:qvisible]");\n const observer = new IntersectionObserver((entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n observer.unobserve(entry.target);\n dispatch(entry.target, "", createEvent("qvisible", entry));\n }\n }\n });\n results.forEach((el) => observer.observe(el));\n }\n }\n};\nconst addEventListener = (el, eventName, handler, capture = false) => {\n el.addEventListener(eventName, handler, { capture, passive: false });\n};\nconst processEventOrNode = (...eventNames) => {\n for (const eventNameOrNode of eventNames) {\n if (typeof eventNameOrNode === "string") {\n if (!events.has(eventNameOrNode)) {\n roots.forEach(\n (root) => addEventListener(root, eventNameOrNode, processDocumentEvent, true)\n );\n addEventListener(win, eventNameOrNode, processWindowEvent, true);\n events.add(eventNameOrNode);\n }\n } else {\n if (!roots.has(eventNameOrNode)) {\n events.forEach(\n (eventName) => addEventListener(eventNameOrNode, eventName, processDocumentEvent, true)\n );\n roots.add(eventNameOrNode);\n }\n }\n }\n};\nif (!("__q_context__" in doc)) {\n doc.__q_context__ = 0;\n const qwikevents = win.qwikevents;\n if (qwikevents) {\n if (Array.isArray(qwikevents)) {\n processEventOrNode(...qwikevents);\n } else {\n processEventOrNode("click", "input");\n }\n }\n win.qwikevents = {\n events,\n roots,\n push: processEventOrNode\n };\n addEventListener(doc, "readystatechange", processReadyStateChange);\n processReadyStateChange();\n}';
1196
+ var QWIK_BACKPATCH_EXECUTOR_MINIFIED = `const t='script[type="qwik/backpatch"]',e=document.currentScript;if(e){const o=e.closest("[q\\\\:container]:not([q\\\\:container=html]):not([q\\\\:container=text])");if(o){const e=o.querySelector(t);if(e){const t=JSON.parse(e.textContent||"[]"),n=document.createTreeWalker(o,NodeFilter.SHOW_ELEMENT);let r=n.currentNode,c=0;for(let e=0;e<t.length;e+=3){const o=t[e],i=t[e+1];let l=t[e+2];for(;c<o;)r=n.nextNode(),c++;const s=r;null==l||!1===l?s.removeAttribute(i):("boolean"==typeof l&&(l=""),s.setAttribute(i,l))}}}}`;
1197
+ var QWIK_BACKPATCH_EXECUTOR_DEBUG = `const BACKPATCH_DATA_SELECTOR = 'script[type="qwik/backpatch"]';
1198
+ const executorScript = document.currentScript;
1199
+ if (executorScript) {
1200
+ const container = executorScript.closest(
1201
+ "[q\\\\:container]:not([q\\\\:container=html]):not([q\\\\:container=text])"
1202
+ );
1203
+ if (container) {
1204
+ const script = container.querySelector(BACKPATCH_DATA_SELECTOR);
1205
+ if (script) {
1206
+ const data = JSON.parse(script.textContent || "[]");
1207
+ const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT);
1208
+ let currentNode = walker.currentNode;
1209
+ let currentNodeIdx = 0;
1210
+ for (let i = 0; i < data.length; i += 3) {
1211
+ const elementIdx = data[i];
1212
+ const attrName = data[i + 1];
1213
+ let value = data[i + 2];
1214
+ while (currentNodeIdx < elementIdx) {
1215
+ currentNode = walker.nextNode();
1216
+ currentNodeIdx++;
1217
+ }
1218
+ const element = currentNode;
1219
+ if (value == null || value === false) {
1220
+ element.removeAttribute(attrName);
1221
+ } else {
1222
+ if (typeof value === "boolean") {
1223
+ value = "";
1224
+ }
1225
+ element.setAttribute(attrName, value);
1226
+ }
1227
+ }
1228
+ }
1229
+ }
1230
+ }`;
1201
1231
  function getQwikLoaderScript(opts = {}) {
1202
1232
  return opts.debug ? QWIK_LOADER_DEFAULT_DEBUG : QWIK_LOADER_DEFAULT_MINIFIED;
1203
1233
  }
@@ -1206,20 +1236,25 @@ var QWIK_PREFETCH_DEBUG = globalThis.QWIK_PREFETCH_DEBUG;
1206
1236
  function getQwikPrefetchWorkerScript(opts = {}) {
1207
1237
  return opts.debug ? QWIK_PREFETCH_DEBUG : QWIK_PREFETCH_MINIFIED;
1208
1238
  }
1239
+ function getQwikBackpatchExecutorScript(opts = {}) {
1240
+ return opts.debug ? QWIK_BACKPATCH_EXECUTOR_DEBUG : QWIK_BACKPATCH_EXECUTOR_MINIFIED;
1241
+ }
1209
1242
 
1210
1243
  // packages/qwik/src/server/ssr-node.ts
1211
1244
  var import_core2 = require("@qwik.dev/core");
1212
1245
  var import_build7 = require("@qwik.dev/core/build");
1213
1246
  var SsrNode = class {
1214
- constructor(parentSsrNode, id, attributesIndex, cleanupQueue, vnodeData) {
1247
+ constructor(parentComponent, id, attributesIndex, cleanupQueue, vnodeData, currentFile) {
1248
+ this.parentComponent = parentComponent;
1215
1249
  this.attributesIndex = attributesIndex;
1216
1250
  this.cleanupQueue = cleanupQueue;
1217
1251
  this.vnodeData = vnodeData;
1252
+ this.currentFile = currentFile;
1218
1253
  var _a;
1219
- this.parentSsrNode = parentSsrNode;
1220
- (_a = this.parentSsrNode) == null ? void 0 : _a.addChild(this);
1221
1254
  this.id = id;
1255
+ this.flags = 1 /* Updatable */;
1222
1256
  this.attrs = this.attributesIndex >= 0 ? this.vnodeData[this.attributesIndex] : import_core2._EMPTY_ARRAY;
1257
+ (_a = this.parentComponent) == null ? void 0 : _a.addChild(this);
1223
1258
  if (import_build7.isDev && id.indexOf("undefined") != -1) {
1224
1259
  throw new Error(`Invalid SSR node id: ${id}`);
1225
1260
  }
@@ -1231,7 +1266,7 @@ var SsrNode = class {
1231
1266
  * @param id - Unique id for the node.
1232
1267
  */
1233
1268
  id;
1234
- parentSsrNode;
1269
+ flags;
1235
1270
  children = null;
1236
1271
  attrs;
1237
1272
  /** Local props which don't serialize; */
@@ -1285,18 +1320,30 @@ var SsrNode = class {
1285
1320
  }
1286
1321
  this.children.push(child);
1287
1322
  }
1323
+ setTreeNonUpdatable() {
1324
+ this.flags &= ~1 /* Updatable */;
1325
+ if (this.children) {
1326
+ for (const child of this.children) {
1327
+ child.setTreeNonUpdatable();
1328
+ }
1329
+ }
1330
+ }
1288
1331
  toString() {
1289
- let stringifiedAttrs = "";
1290
- for (let i = 0; i < this.attrs.length; i += 2) {
1291
- const key = this.attrs[i];
1292
- const value = this.attrs[i + 1];
1293
- stringifiedAttrs += `${key}=`;
1294
- stringifiedAttrs += `${typeof value === "string" || typeof value === "number" ? JSON.stringify(value) : "*"}`;
1295
- if (i < this.attrs.length - 2) {
1296
- stringifiedAttrs += ", ";
1332
+ if (import_build7.isDev) {
1333
+ let stringifiedAttrs = "";
1334
+ for (let i = 0; i < this.attrs.length; i += 2) {
1335
+ const key = this.attrs[i];
1336
+ const value = this.attrs[i + 1];
1337
+ stringifiedAttrs += `${key}=`;
1338
+ stringifiedAttrs += `${typeof value === "string" || typeof value === "number" ? JSON.stringify(value) : "*"}`;
1339
+ if (i < this.attrs.length - 2) {
1340
+ stringifiedAttrs += ", ";
1341
+ }
1297
1342
  }
1343
+ return `<SSRNode id="${this.id}" ${stringifiedAttrs} />`;
1344
+ } else {
1345
+ return `<SSRNode id="${this.id}" />`;
1298
1346
  }
1299
- return `SSRNode [<${this.id}> ${stringifiedAttrs}]`;
1300
1347
  }
1301
1348
  };
1302
1349
  var DomRef = class {
@@ -1716,7 +1763,7 @@ function vNodeData_openElement(vNodeData) {
1716
1763
  vNodeData.push([], WRITE_ELEMENT_ATTRS);
1717
1764
  vNodeData[0] |= 4 /* ELEMENT_NODE */;
1718
1765
  }
1719
- function vNodeData_createSsrNodeReference(currentComponentNode, vNodeData, depthFirstElementIdx, cleanupQueue) {
1766
+ function vNodeData_createSsrNodeReference(currentComponentNode, vNodeData, depthFirstElementIdx, cleanupQueue, currentFile) {
1720
1767
  vNodeData[0] |= 8 /* REFERENCE */;
1721
1768
  const stack = [-1];
1722
1769
  let attributesIndex = -1;
@@ -1747,7 +1794,14 @@ function vNodeData_createSsrNodeReference(currentComponentNode, vNodeData, depth
1747
1794
  }
1748
1795
  }
1749
1796
  }
1750
- return new SsrNode(currentComponentNode, refId, attributesIndex, cleanupQueue, vNodeData);
1797
+ return new SsrNode(
1798
+ currentComponentNode,
1799
+ refId,
1800
+ attributesIndex,
1801
+ cleanupQueue,
1802
+ vNodeData,
1803
+ currentFile
1804
+ );
1751
1805
  }
1752
1806
  var ALPHANUMERIC = [];
1753
1807
  function encodeAsAlphanumeric(value) {
@@ -2069,6 +2123,8 @@ var SSRContainer = class extends import_core4._SharedContainer {
2069
2123
  lastNode = null;
2070
2124
  currentComponentNode = null;
2071
2125
  styleIds = /* @__PURE__ */ new Set();
2126
+ isBackpatchExecutorEmitted = false;
2127
+ backpatchMap = /* @__PURE__ */ new Map();
2072
2128
  currentElementFrame = null;
2073
2129
  renderTimer;
2074
2130
  /**
@@ -2087,18 +2143,7 @@ var SSRContainer = class extends import_core4._SharedContainer {
2087
2143
  // Temporary flag to find missing roots after the state was serialized
2088
2144
  $noMoreRoots$ = false;
2089
2145
  constructor(opts) {
2090
- super(
2091
- () => {
2092
- try {
2093
- return this.$scheduler$(255 /* WAIT_FOR_ALL */);
2094
- } catch (e) {
2095
- this.handleError(e, null);
2096
- }
2097
- },
2098
- () => null,
2099
- opts.renderOptions.serverData ?? EMPTY_OBJ,
2100
- opts.locale
2101
- );
2146
+ super(() => null, opts.renderOptions.serverData ?? EMPTY_OBJ, opts.locale);
2102
2147
  this.symbolToChunkResolver = (symbol) => {
2103
2148
  const idx = symbol.lastIndexOf("_");
2104
2149
  const chunk = this.resolvedManifest.mapper[idx == -1 ? symbol : symbol.substring(idx + 1)];
@@ -2125,6 +2170,16 @@ var SSRContainer = class extends import_core4._SharedContainer {
2125
2170
  handleError(err, _$host$) {
2126
2171
  throw err;
2127
2172
  }
2173
+ addBackpatchEntry(ssrNodeId, attrName, serializedValue) {
2174
+ const elementIndex = parseInt(ssrNodeId, 10);
2175
+ const entry = {
2176
+ attrName,
2177
+ value: serializedValue
2178
+ };
2179
+ const entries = this.backpatchMap.get(elementIndex) || [];
2180
+ entries.push(entry);
2181
+ this.backpatchMap.set(elementIndex, entries);
2182
+ }
2128
2183
  async render(jsx) {
2129
2184
  this.openContainer();
2130
2185
  await (0, import_core4._walkJSX)(this, jsx, {
@@ -2149,13 +2204,13 @@ var SSRContainer = class extends import_core4._SharedContainer {
2149
2204
  if (ctx != null && mapArray_has(ctx, contextId.id, 0)) {
2150
2205
  return mapArray_get(ctx, contextId.id, 0);
2151
2206
  }
2152
- ssrNode = ssrNode.parentSsrNode;
2207
+ ssrNode = ssrNode.parentComponent;
2153
2208
  }
2154
2209
  return void 0;
2155
2210
  }
2156
2211
  getParentHost(host) {
2157
2212
  const ssrNode = host;
2158
- return ssrNode.parentSsrNode;
2213
+ return ssrNode.parentComponent;
2159
2214
  }
2160
2215
  setHostProp(host, name, value) {
2161
2216
  const ssrNode = host;
@@ -2209,6 +2264,7 @@ var SSRContainer = class extends import_core4._SharedContainer {
2209
2264
  vNodeData_openElement(this.currentElementFrame.vNodeData);
2210
2265
  this.write("<");
2211
2266
  this.write(elementName);
2267
+ const lastNode = this.getOrCreateLastNode();
2212
2268
  if (varAttrs) {
2213
2269
  innerHTML = this.writeAttrs(elementName, varAttrs, false, currentFile);
2214
2270
  }
@@ -2218,7 +2274,9 @@ var SSRContainer = class extends import_core4._SharedContainer {
2218
2274
  innerHTML = this.writeAttrs(elementName, constAttrs, true, currentFile) || innerHTML;
2219
2275
  }
2220
2276
  this.write(">");
2221
- this.lastNode = null;
2277
+ if (lastNode) {
2278
+ lastNode.setTreeNonUpdatable();
2279
+ }
2222
2280
  return innerHTML;
2223
2281
  }
2224
2282
  /** Renders closing tag for DOM element */
@@ -2281,6 +2339,9 @@ var SSRContainer = class extends import_core4._SharedContainer {
2281
2339
  /** Writes closing data to vNodeData for fragment boundaries */
2282
2340
  closeFragment() {
2283
2341
  vNodeData_closeFragment(this.currentElementFrame.vNodeData);
2342
+ if (this.currentComponentNode) {
2343
+ this.currentComponentNode.setTreeNonUpdatable();
2344
+ }
2284
2345
  this.lastNode = null;
2285
2346
  }
2286
2347
  openProjection(attrs) {
@@ -2327,7 +2388,7 @@ var SSRContainer = class extends import_core4._SharedContainer {
2327
2388
  const componentFrame = this.componentStack.pop();
2328
2389
  componentFrame.releaseUnclaimedProjections(this.unclaimedProjections);
2329
2390
  this.closeFragment();
2330
- this.currentComponentNode = ((_a = this.currentComponentNode) == null ? void 0 : _a.parentSsrNode) || null;
2391
+ this.currentComponentNode = ((_a = this.currentComponentNode) == null ? void 0 : _a.parentComponent) || null;
2331
2392
  }
2332
2393
  /** Write a text node with correct escaping. Save the length of the text node in the vNodeData. */
2333
2394
  textNode(text) {
@@ -2354,7 +2415,8 @@ var SSRContainer = class extends import_core4._SharedContainer {
2354
2415
  this.currentElementFrame.vNodeData,
2355
2416
  // we start at -1, so we need to add +1
2356
2417
  this.currentElementFrame.depthFirstElementIdx + 1,
2357
- this.cleanupQueue
2418
+ this.cleanupQueue,
2419
+ this.currentElementFrame.currentFile
2358
2420
  );
2359
2421
  }
2360
2422
  return this.lastNode;
@@ -2418,6 +2480,8 @@ var SSRContainer = class extends import_core4._SharedContainer {
2418
2480
  this.emitVNodeData();
2419
2481
  preloaderPost(this, this.renderOptions, (_a = this.$serverData$) == null ? void 0 : _a.nonce);
2420
2482
  this.emitSyncFnsData();
2483
+ this.emitPatchDataIfNeeded();
2484
+ this.emitExecutorIfNeeded();
2421
2485
  this.emitQwikLoaderAtBottomIfNeeded();
2422
2486
  })
2423
2487
  );
@@ -2588,6 +2652,40 @@ var SSRContainer = class extends import_core4._SharedContainer {
2588
2652
  this.closeElement();
2589
2653
  }
2590
2654
  }
2655
+ emitPatchDataIfNeeded() {
2656
+ var _a;
2657
+ const patches = [];
2658
+ for (const [elementIndex, backpatchEntries] of this.backpatchMap) {
2659
+ for (const backpatchEntry of backpatchEntries) {
2660
+ patches.push(elementIndex, backpatchEntry.attrName, backpatchEntry.value);
2661
+ }
2662
+ }
2663
+ this.backpatchMap.clear();
2664
+ if (patches.length > 0) {
2665
+ this.isBackpatchExecutorEmitted = true;
2666
+ const scriptAttrs = ["type", ELEMENT_BACKPATCH_DATA];
2667
+ if ((_a = this.renderOptions.serverData) == null ? void 0 : _a.nonce) {
2668
+ scriptAttrs.push("nonce", this.renderOptions.serverData.nonce);
2669
+ }
2670
+ this.openElement("script", scriptAttrs);
2671
+ this.write(JSON.stringify(patches));
2672
+ this.closeElement();
2673
+ }
2674
+ }
2675
+ emitExecutorIfNeeded() {
2676
+ var _a;
2677
+ if (!this.isBackpatchExecutorEmitted) {
2678
+ return;
2679
+ }
2680
+ const scriptAttrs = ["type", "text/javascript"];
2681
+ if ((_a = this.renderOptions.serverData) == null ? void 0 : _a.nonce) {
2682
+ scriptAttrs.push("nonce", this.renderOptions.serverData.nonce);
2683
+ }
2684
+ this.openElement("script", scriptAttrs);
2685
+ const backpatchScript = getQwikBackpatchExecutorScript({ debug: import_build8.isDev });
2686
+ this.write(backpatchScript);
2687
+ this.closeElement();
2688
+ }
2591
2689
  emitPreloaderPre() {
2592
2690
  var _a;
2593
2691
  preloaderPre(this, this.renderOptions.preloader, (_a = this.renderOptions.serverData) == null ? void 0 : _a.nonce);
@@ -2780,7 +2878,8 @@ var SSRContainer = class extends import_core4._SharedContainer {
2780
2878
  parent: this.currentElementFrame,
2781
2879
  elementName,
2782
2880
  depthFirstElementIdx,
2783
- vNodeData: [0 /* NONE */]
2881
+ vNodeData: [0 /* NONE */],
2882
+ currentFile: import_build8.isDev ? currentFile || null : null
2784
2883
  };
2785
2884
  this.currentElementFrame = frame;
2786
2885
  this.vNodeDatas.push(frame.vNodeData);
@@ -2951,6 +3050,7 @@ var renderToStream = async (jsx, opts) => {
2951
3050
  });
2952
3051
  await setServerPlatform(opts, resolvedManifest);
2953
3052
  await ssrContainer.render(jsx);
3053
+ await ssrContainer.$scheduler$(255 /* WAIT_FOR_QUEUE */).$returnValue$;
2954
3054
  flush();
2955
3055
  const snapshotResult = getSnapshotResult(ssrContainer);
2956
3056
  const isDynamic = snapshotResult.resources.some((r) => r._cache !== Infinity);
@@ -3099,6 +3199,7 @@ async function setServerPlatform2(manifest) {
3099
3199
  }
3100
3200
  // Annotate the CommonJS export names for ESM import in node:
3101
3201
  0 && (module.exports = {
3202
+ getQwikBackpatchExecutorScript,
3102
3203
  getQwikLoaderScript,
3103
3204
  getQwikPrefetchWorkerScript,
3104
3205
  renderToStream,
package/dist/server.d.ts CHANGED
@@ -35,6 +35,15 @@ declare type FunctionComponent<P = unknown> = {
35
35
  renderFn(props: P, key: string | null, flags: number, dev?: DevJSX): JSXOutput;
36
36
  }['renderFn'];
37
37
 
38
+ /**
39
+ * Provides the `backpatch-executor.js` executor script as a string.
40
+ *
41
+ * @public
42
+ */
43
+ export declare function getQwikBackpatchExecutorScript(opts?: {
44
+ debug?: boolean;
45
+ }): string;
46
+
38
47
  /**
39
48
  * Provides the `qwikloader.js` file as a string. Useful for tooling to inline the qwikloader script
40
49
  * into HTML.