solid-js 1.4.0-beta.1 → 1.4.0-beta.4

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "solid-js",
3
3
  "description": "A declarative JavaScript library for building user interfaces.",
4
- "version": "1.4.0-beta.1",
4
+ "version": "1.4.0-beta.4",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
7
7
  "homepage": "https://solidjs.com",
@@ -27,6 +27,8 @@
27
27
  "web/types",
28
28
  "h/dist",
29
29
  "h/types",
30
+ "h/jsx-runtime/dist",
31
+ "h/jsx-runtime/types",
30
32
  "html/dist",
31
33
  "html/types",
32
34
  "universal/dist",
@@ -111,6 +113,10 @@
111
113
  "import": "./h/dist/h.js",
112
114
  "require": "./h/dist/h.cjs"
113
115
  },
116
+ "./h/jsx-runtime": {
117
+ "import": "./h/dist/jsx.js",
118
+ "require": "./h/dist/jsx.cjs"
119
+ },
114
120
  "./h/dist/*": "./h/dist/*",
115
121
  "./html": {
116
122
  "import": "./html/dist/html.js",
@@ -120,15 +126,16 @@
120
126
  },
121
127
  "scripts": {
122
128
  "prebuild": "npm run clean",
123
- "clean": "rimraf dist/ types/ coverage/ store/dist/ store/types/ web/dist/ web/types/ h/dist/ h/types/ html/dist/ html/types/",
129
+ "clean": "rimraf dist/ types/ coverage/ store/dist/ store/types/ web/dist/ web/types/ h/dist/ h/types/ h/jsx-runtime/dist h/jsx-runtime/types html/dist/ html/types/",
124
130
  "build": "npm-run-all -cnl build:*",
125
131
  "build:link": "symlink-dir . node_modules/solid-js",
126
- "build:js": "ncp ../../node_modules/dom-expressions/src/jsx.d.ts ./src/jsx.d.ts && rollup -c",
132
+ "build:js": "ncp ../../node_modules/dom-expressions/src/jsx.d.ts ./src/jsx.d.ts && ncp ../../node_modules/dom-expressions/src/jsx-standard.d.ts ./h/jsx-runtime/src/jsx.d.ts && rollup -c",
127
133
  "build:types": "tsc --project ./tsconfig.build.json",
128
134
  "build:types-store": "tsc --project ./store/tsconfig.build.json && tsconfig-replace-paths --project ./store/tsconfig.types.json",
129
135
  "build:types-web": "tsc --project ./web/tsconfig.build.json && tsconfig-replace-paths --project ./web/tsconfig.types.json",
130
136
  "build:types-html": "tsc --project ./html/tsconfig.json",
131
137
  "build:types-h": "tsc --project ./h/tsconfig.json",
138
+ "build:types-jsx": "tsc --project ./h/jsx-runtime/tsconfig.json",
132
139
  "build:types-universal": "tsc --project ./universal/tsconfig.json",
133
140
  "bench": "node --allow-natives-syntax bench/bench.cjs",
134
141
  "test": "jest && npm run test:types",
@@ -144,5 +151,5 @@
144
151
  "compiler",
145
152
  "performance"
146
153
  ],
147
- "gitHead": "34628200f7c8e0a329905688a455848096a3e429"
154
+ "gitHead": "c569a8d57962e99a906ed170716055ac6fe929ef"
148
155
  }
@@ -384,30 +384,6 @@ function produce(fn) {
384
384
  return state;
385
385
  };
386
386
  }
387
- function splice(start, deleteCount = 0, ...items) {
388
- return state => {
389
- if (Array.isArray(state)) {
390
- if (start < 0) start = start + state.length;
391
- if (deleteCount < 0) deleteCount = 0;
392
- const stop = start + deleteCount;
393
- if (deleteCount >= items.length) {
394
- for (let i = stop; i < state.length; i++) {
395
- setProperty(state, start + i - stop, state[i]);
396
- }
397
- } else {
398
- const offset = items.length - deleteCount;
399
- for (let i = state.length - 1; i >= stop; i--) {
400
- setProperty(state, i + offset, state[i]);
401
- }
402
- }
403
- for (let i = 0; i < items.length; i++) {
404
- setProperty(state, start + i, items[i]);
405
- }
406
- setProperty(state, "length", state.length + items.length - deleteCount);
407
- }
408
- return state;
409
- };
410
- }
411
387
 
412
388
  exports.$RAW = $RAW;
413
389
  exports.createMutable = createMutable;
@@ -415,5 +391,4 @@ exports.createStore = createStore;
415
391
  exports.modifyMutable = modifyMutable;
416
392
  exports.produce = produce;
417
393
  exports.reconcile = reconcile;
418
- exports.splice = splice;
419
394
  exports.unwrap = unwrap;
package/store/dist/dev.js CHANGED
@@ -380,29 +380,5 @@ function produce(fn) {
380
380
  return state;
381
381
  };
382
382
  }
383
- function splice(start, deleteCount = 0, ...items) {
384
- return state => {
385
- if (Array.isArray(state)) {
386
- if (start < 0) start = start + state.length;
387
- if (deleteCount < 0) deleteCount = 0;
388
- const stop = start + deleteCount;
389
- if (deleteCount >= items.length) {
390
- for (let i = stop; i < state.length; i++) {
391
- setProperty(state, start + i - stop, state[i]);
392
- }
393
- } else {
394
- const offset = items.length - deleteCount;
395
- for (let i = state.length - 1; i >= stop; i--) {
396
- setProperty(state, i + offset, state[i]);
397
- }
398
- }
399
- for (let i = 0; i < items.length; i++) {
400
- setProperty(state, start + i, items[i]);
401
- }
402
- setProperty(state, "length", state.length + items.length - deleteCount);
403
- }
404
- return state;
405
- };
406
- }
407
383
 
408
- export { $RAW, createMutable, createStore, modifyMutable, produce, reconcile, splice, unwrap };
384
+ export { $RAW, createMutable, createStore, modifyMutable, produce, reconcile, unwrap };
@@ -362,30 +362,6 @@ function produce(fn) {
362
362
  return state;
363
363
  };
364
364
  }
365
- function splice(start, deleteCount = 0, ...items) {
366
- return state => {
367
- if (Array.isArray(state)) {
368
- if (start < 0) start = start + state.length;
369
- if (deleteCount < 0) deleteCount = 0;
370
- const stop = start + deleteCount;
371
- if (deleteCount >= items.length) {
372
- for (let i = stop; i < state.length; i++) {
373
- setProperty(state, start + i - stop, state[i]);
374
- }
375
- } else {
376
- const offset = items.length - deleteCount;
377
- for (let i = state.length - 1; i >= stop; i--) {
378
- setProperty(state, i + offset, state[i]);
379
- }
380
- }
381
- for (let i = 0; i < items.length; i++) {
382
- setProperty(state, start + i, items[i]);
383
- }
384
- setProperty(state, "length", state.length + items.length - deleteCount);
385
- }
386
- return state;
387
- };
388
- }
389
365
 
390
366
  exports.$RAW = $RAW;
391
367
  exports.createMutable = createMutable;
@@ -393,5 +369,4 @@ exports.createStore = createStore;
393
369
  exports.modifyMutable = modifyMutable;
394
370
  exports.produce = produce;
395
371
  exports.reconcile = reconcile;
396
- exports.splice = splice;
397
372
  exports.unwrap = unwrap;
@@ -358,29 +358,5 @@ function produce(fn) {
358
358
  return state;
359
359
  };
360
360
  }
361
- function splice(start, deleteCount = 0, ...items) {
362
- return state => {
363
- if (Array.isArray(state)) {
364
- if (start < 0) start = start + state.length;
365
- if (deleteCount < 0) deleteCount = 0;
366
- const stop = start + deleteCount;
367
- if (deleteCount >= items.length) {
368
- for (let i = stop; i < state.length; i++) {
369
- setProperty(state, start + i - stop, state[i]);
370
- }
371
- } else {
372
- const offset = items.length - deleteCount;
373
- for (let i = state.length - 1; i >= stop; i--) {
374
- setProperty(state, i + offset, state[i]);
375
- }
376
- }
377
- for (let i = 0; i < items.length; i++) {
378
- setProperty(state, start + i, items[i]);
379
- }
380
- setProperty(state, "length", state.length + items.length - deleteCount);
381
- }
382
- return state;
383
- };
384
- }
385
361
 
386
- export { $RAW, createMutable, createStore, modifyMutable, produce, reconcile, splice, unwrap };
362
+ export { $RAW, createMutable, createStore, modifyMutable, produce, reconcile, unwrap };
@@ -5,4 +5,3 @@ export declare type ReconcileOptions = {
5
5
  };
6
6
  export declare function reconcile<T extends U, U>(value: T, options?: ReconcileOptions): (state: U) => T;
7
7
  export declare function produce<T>(fn: (state: DeepMutable<T>) => void): (state: T) => T;
8
- export declare function splice<T extends U, U>(start: number, deleteCount?: number, ...items: T[]): (state: readonly U[]) => T[];
@@ -2,4 +2,4 @@ import { StoreNode } from "./store";
2
2
  export declare function createMutable<T extends StoreNode>(state: T, options?: {
3
3
  name?: string;
4
4
  }): T;
5
- export declare function modifyMutable<T extends U, U>(state: T, modifier: (state: U) => T): void;
5
+ export declare function modifyMutable<T>(state: T, modifier: (state: T) => T): void;
@@ -216,10 +216,12 @@ export declare type ResourceFetcherInfo<T> = {
216
216
  export declare type ResourceOptions<T> = undefined extends T ? {
217
217
  initialValue?: T;
218
218
  name?: string;
219
+ deferStream?: boolean;
219
220
  onHydrated?: <S, T>(k: S, info: ResourceFetcherInfo<T>) => void;
220
221
  } : {
221
222
  initialValue: T;
222
223
  name?: string;
224
+ deferStream?: boolean;
223
225
  onHydrated?: <S, T>(k: S, info: ResourceFetcherInfo<T>) => void;
224
226
  };
225
227
  /**
@@ -92,10 +92,12 @@ export declare type ResourceFetcherInfo<T> = {
92
92
  export declare type ResourceOptions<T> = undefined extends T ? {
93
93
  initialValue?: T;
94
94
  name?: string;
95
+ deferStream?: boolean;
95
96
  onHydrated?: <S, T>(k: S, info: ResourceFetcherInfo<T>) => void;
96
97
  } : {
97
98
  initialValue: T;
98
99
  name?: string;
100
+ deferStream?: boolean;
99
101
  onHydrated?: <S, T>(k: S, info: ResourceFetcherInfo<T>) => void;
100
102
  };
101
103
  export declare function createResource<T, S = true>(fetcher: ResourceFetcher<S, T>, options?: ResourceOptions<undefined>): ResourceReturn<T | undefined>;
@@ -116,7 +118,7 @@ export declare function useTransition(): [() => boolean, (fn: () => any) => void
116
118
  declare type HydrationContext = {
117
119
  id: string;
118
120
  count: number;
119
- writeResource?: (id: string, v: Promise<any> | any, error?: boolean) => void;
121
+ writeResource?: (id: string, v: Promise<any> | any, error?: boolean, deferStream?: boolean) => void;
120
122
  resources: Record<string, any>;
121
123
  suspense: Record<string, SuspenseContextType>;
122
124
  registerFragment: (v: string) => (v?: string, err?: any) => boolean;
@@ -269,8 +269,8 @@ function renderToStringAsync(code, options = {}) {
269
269
  nonce,
270
270
  writeResource(id, p, error) {
271
271
  if (error) return scripts += `_$HY.set("${id}", ${serializeError(p)});`;
272
- if (!p || typeof p !== "object" || !("then" in p)) return scripts += serializeSet(dedupe, id, p);
273
- p.then(d => scripts += serializeSet(dedupe, id, d)).catch(() => scripts += `_$HY.set("${id}", {});`);
272
+ if (!p || typeof p !== "object" || !("then" in p)) return (scripts += serializeSet(dedupe, id, p)) + ";";
273
+ p.then(d => scripts += serializeSet(dedupe, id, d) + ";").catch(() => scripts += `_$HY.set("${id}", {});`);
274
274
  }
275
275
  };
276
276
  const timeout = new Promise((_, reject) => setTimeout(() => reject("renderToString timed out"), timeoutMs));
@@ -318,6 +318,7 @@ function renderToStream(code, options = {}) {
318
318
  } = options;
319
319
  const tmp = [];
320
320
  const tasks = [];
321
+ const blockingResources = [];
321
322
  const registry = new Map();
322
323
  const dedupe = new WeakMap();
323
324
  const checkEnd = () => {
@@ -332,6 +333,13 @@ function renderToStream(code, options = {}) {
332
333
  completed = true;
333
334
  }
334
335
  };
336
+ const pushTask = task => {
337
+ tasks.push(task);
338
+ if (!scheduled) {
339
+ Promise.resolve().then(writeTasks);
340
+ scheduled = true;
341
+ }
342
+ };
335
343
  const writeTasks = () => {
336
344
  if (tasks.length && !completed) {
337
345
  buffer.write(`<script${nonce ? ` nonce="${nonce}"` : ""}>${tasks.join(";")}</script>`);
@@ -340,6 +348,7 @@ function renderToStream(code, options = {}) {
340
348
  scheduled = false;
341
349
  };
342
350
  let writable;
351
+ let firstFlushed = false;
343
352
  let completed = false;
344
353
  let scriptFlushed = false;
345
354
  let scheduled = true;
@@ -357,45 +366,45 @@ function renderToStream(code, options = {}) {
357
366
  suspense: {},
358
367
  assets: [],
359
368
  nonce,
360
- writeResource(id, p, error) {
361
- if (!scheduled) {
362
- Promise.resolve().then(writeTasks);
363
- scheduled = true;
364
- }
365
- if (error) return tasks.push(`_$HY.set("${id}", ${serializeError(p)})`);
366
- if (!p || typeof p !== "object" || !("then" in p)) return tasks.push(serializeSet(dedupe, id, p));
367
- tasks.push(`_$HY.init("${id}")`);
369
+ writeResource(id, p, error, wait) {
370
+ if (error) return pushTask(`_$HY.set("${id}", ${serializeError(p)})`);
371
+ if (!p || typeof p !== "object" || !("then" in p)) return pushTask(serializeSet(dedupe, id, p));
372
+ if (wait && !firstFlushed) blockingResources.push(p);else pushTask(`_$HY.init("${id}")`);
368
373
  p.then(d => {
369
- !completed && buffer.write(`<script${nonce ? ` nonce="${nonce}"` : ""}>${serializeSet(dedupe, id, d)}</script>`);
374
+ !completed && pushTask(serializeSet(dedupe, id, d));
370
375
  }).catch(() => {
371
- !completed && buffer.write(`<script${nonce ? ` nonce="${nonce}"` : ""}>_$HY.set("${id}", {})</script>`);
376
+ !completed && pushTask(`_$HY.set("${id}", {})`);
372
377
  });
373
378
  },
374
379
  registerFragment(key) {
375
- registry.set(key, []);
376
- if (!scheduled) {
377
- Promise.resolve().then(writeTasks);
378
- scheduled = true;
380
+ if (!registry.has(key)) {
381
+ registry.set(key, []);
382
+ pushTask(`_$HY.init("${key}")`);
379
383
  }
380
- tasks.push(`_$HY.init("${key}")`);
381
384
  return (value, error) => {
382
385
  if (registry.has(key)) {
383
386
  const keys = registry.get(key);
384
387
  registry.delete(key);
385
388
  if (waitForFragments(registry, key)) return;
386
389
  if ((value !== undefined || error) && !completed) {
387
- buffer.write(`<div hidden id="${key}">${value !== undefined ? value : " "}</div><script${nonce ? ` nonce="${nonce}"` : ""}>${!scriptFlushed ? REPLACE_SCRIPT : ""}${keys.length ? keys.map(k => `_$HY.unset("${k}");`) : ""}$df("${key}"${error ? "," + serializeError(error) : ""})</script>`);
388
- scriptFlushed = true;
390
+ if (!firstFlushed) {
391
+ Promise.resolve().then(() => html = replacePlaceholder(html, key, value !== undefined ? value : ""));
392
+ pushTask(`${keys.length ? keys.map(k => `_$HY.unset("${k}");`) : ""}_$HY.set("${key}",${error ? serializeError(error) : "null"})`);
393
+ } else {
394
+ buffer.write(`<div hidden id="${key}">${value !== undefined ? value : " "}</div>`);
395
+ pushTask(`${keys.length ? keys.map(k => `_$HY.unset("${k}")`).join(";") : ""}$df("${key}"${error ? "," + serializeError(error) : ""})${!scriptFlushed ? ";" + REPLACE_SCRIPT : ""}`);
396
+ scriptFlushed = true;
397
+ }
389
398
  }
390
399
  }
391
- checkEnd();
400
+ if (firstFlushed) checkEnd();
392
401
  return true;
393
402
  };
394
403
  }
395
404
  };
396
405
  let html = resolveSSRNode(escape(code()));
397
- html = injectAssets(solidJs.sharedConfig.context.assets, html);
398
- Promise.resolve().then(() => {
406
+ function doShell() {
407
+ html = injectAssets(solidJs.sharedConfig.context.assets, html);
399
408
  if (tasks.length) html = injectScripts(html, tasks.join(";"), nonce);
400
409
  buffer.write(html);
401
410
  tasks.length = 0;
@@ -405,29 +414,37 @@ function renderToStream(code, options = {}) {
405
414
  !completed && buffer.write(v);
406
415
  }
407
416
  });
408
- });
417
+ }
409
418
  return {
410
419
  pipe(w) {
411
- buffer = writable = w;
412
- tmp.forEach(chunk => buffer.write(chunk));
413
- if (completed) writable.end();else setTimeout(checkEnd);
420
+ Promise.allSettled(blockingResources).then(() => {
421
+ doShell();
422
+ buffer = writable = w;
423
+ tmp.forEach(chunk => buffer.write(chunk));
424
+ firstFlushed = true;
425
+ if (completed) writable.end();else setTimeout(checkEnd);
426
+ });
414
427
  },
415
428
  pipeTo(w) {
416
- const encoder = new TextEncoder();
417
- const writer = w.getWriter();
418
- writable = {
419
- end() {
420
- writer.releaseLock();
421
- w.close();
422
- }
423
- };
424
- buffer = {
425
- write(payload) {
426
- writer.write(encoder.encode(payload));
427
- }
428
- };
429
- tmp.forEach(chunk => buffer.write(chunk));
430
- if (completed) writable.end();else setTimeout(checkEnd);
429
+ Promise.allSettled(blockingResources).then(() => {
430
+ doShell();
431
+ const encoder = new TextEncoder();
432
+ const writer = w.getWriter();
433
+ writable = {
434
+ end() {
435
+ writer.releaseLock();
436
+ w.close();
437
+ }
438
+ };
439
+ buffer = {
440
+ write(payload) {
441
+ writer.write(encoder.encode(payload));
442
+ }
443
+ };
444
+ tmp.forEach(chunk => buffer.write(chunk));
445
+ firstFlushed = true;
446
+ if (completed) writable.end();else setTimeout(checkEnd);
447
+ });
431
448
  }
432
449
  };
433
450
  }
@@ -638,9 +655,26 @@ function waitForFragments(registry, key) {
638
655
  }
639
656
  function serializeSet(registry, key, value) {
640
657
  const exist = registry.get(value);
641
- if (exist) return `_$HY.set("${key}", _$HY.r["${exist}"][0]);`;
658
+ if (exist) return `_$HY.set("${key}", _$HY.r["${exist}"][0])`;
642
659
  value !== null && typeof value === "object" && registry.set(value, key);
643
- return `_$HY.set("${key}", ${devalue(value)});`;
660
+ return `_$HY.set("${key}", ${devalue(value)})`;
661
+ }
662
+ function replacePlaceholder(html, key, value) {
663
+ const nextRegex = /(<[/]?span[^>]*>)/g;
664
+ const marker = `<span id="pl-${key}">`;
665
+ const first = html.indexOf(marker);
666
+ if (first === -1) return html;
667
+ nextRegex.lastIndex = first + marker.length;
668
+ let match;
669
+ let open = 0,
670
+ close = 0;
671
+ while (match = nextRegex.exec(html)) {
672
+ if (match[0][1] === "/") {
673
+ close++;
674
+ if (close > open) break;
675
+ } else open++;
676
+ }
677
+ return html.slice(0, first) + value + html.slice(nextRegex.lastIndex);
644
678
  }
645
679
  function pipeToNodeWritable(code, writable, options = {}) {
646
680
  if (options.onReady) {
@@ -266,8 +266,8 @@ function renderToStringAsync(code, options = {}) {
266
266
  nonce,
267
267
  writeResource(id, p, error) {
268
268
  if (error) return scripts += `_$HY.set("${id}", ${serializeError(p)});`;
269
- if (!p || typeof p !== "object" || !("then" in p)) return scripts += serializeSet(dedupe, id, p);
270
- p.then(d => scripts += serializeSet(dedupe, id, d)).catch(() => scripts += `_$HY.set("${id}", {});`);
269
+ if (!p || typeof p !== "object" || !("then" in p)) return (scripts += serializeSet(dedupe, id, p)) + ";";
270
+ p.then(d => scripts += serializeSet(dedupe, id, d) + ";").catch(() => scripts += `_$HY.set("${id}", {});`);
271
271
  }
272
272
  };
273
273
  const timeout = new Promise((_, reject) => setTimeout(() => reject("renderToString timed out"), timeoutMs));
@@ -315,6 +315,7 @@ function renderToStream(code, options = {}) {
315
315
  } = options;
316
316
  const tmp = [];
317
317
  const tasks = [];
318
+ const blockingResources = [];
318
319
  const registry = new Map();
319
320
  const dedupe = new WeakMap();
320
321
  const checkEnd = () => {
@@ -329,6 +330,13 @@ function renderToStream(code, options = {}) {
329
330
  completed = true;
330
331
  }
331
332
  };
333
+ const pushTask = task => {
334
+ tasks.push(task);
335
+ if (!scheduled) {
336
+ Promise.resolve().then(writeTasks);
337
+ scheduled = true;
338
+ }
339
+ };
332
340
  const writeTasks = () => {
333
341
  if (tasks.length && !completed) {
334
342
  buffer.write(`<script${nonce ? ` nonce="${nonce}"` : ""}>${tasks.join(";")}</script>`);
@@ -337,6 +345,7 @@ function renderToStream(code, options = {}) {
337
345
  scheduled = false;
338
346
  };
339
347
  let writable;
348
+ let firstFlushed = false;
340
349
  let completed = false;
341
350
  let scriptFlushed = false;
342
351
  let scheduled = true;
@@ -354,45 +363,45 @@ function renderToStream(code, options = {}) {
354
363
  suspense: {},
355
364
  assets: [],
356
365
  nonce,
357
- writeResource(id, p, error) {
358
- if (!scheduled) {
359
- Promise.resolve().then(writeTasks);
360
- scheduled = true;
361
- }
362
- if (error) return tasks.push(`_$HY.set("${id}", ${serializeError(p)})`);
363
- if (!p || typeof p !== "object" || !("then" in p)) return tasks.push(serializeSet(dedupe, id, p));
364
- tasks.push(`_$HY.init("${id}")`);
366
+ writeResource(id, p, error, wait) {
367
+ if (error) return pushTask(`_$HY.set("${id}", ${serializeError(p)})`);
368
+ if (!p || typeof p !== "object" || !("then" in p)) return pushTask(serializeSet(dedupe, id, p));
369
+ if (wait && !firstFlushed) blockingResources.push(p);else pushTask(`_$HY.init("${id}")`);
365
370
  p.then(d => {
366
- !completed && buffer.write(`<script${nonce ? ` nonce="${nonce}"` : ""}>${serializeSet(dedupe, id, d)}</script>`);
371
+ !completed && pushTask(serializeSet(dedupe, id, d));
367
372
  }).catch(() => {
368
- !completed && buffer.write(`<script${nonce ? ` nonce="${nonce}"` : ""}>_$HY.set("${id}", {})</script>`);
373
+ !completed && pushTask(`_$HY.set("${id}", {})`);
369
374
  });
370
375
  },
371
376
  registerFragment(key) {
372
- registry.set(key, []);
373
- if (!scheduled) {
374
- Promise.resolve().then(writeTasks);
375
- scheduled = true;
377
+ if (!registry.has(key)) {
378
+ registry.set(key, []);
379
+ pushTask(`_$HY.init("${key}")`);
376
380
  }
377
- tasks.push(`_$HY.init("${key}")`);
378
381
  return (value, error) => {
379
382
  if (registry.has(key)) {
380
383
  const keys = registry.get(key);
381
384
  registry.delete(key);
382
385
  if (waitForFragments(registry, key)) return;
383
386
  if ((value !== undefined || error) && !completed) {
384
- buffer.write(`<div hidden id="${key}">${value !== undefined ? value : " "}</div><script${nonce ? ` nonce="${nonce}"` : ""}>${!scriptFlushed ? REPLACE_SCRIPT : ""}${keys.length ? keys.map(k => `_$HY.unset("${k}");`) : ""}$df("${key}"${error ? "," + serializeError(error) : ""})</script>`);
385
- scriptFlushed = true;
387
+ if (!firstFlushed) {
388
+ Promise.resolve().then(() => html = replacePlaceholder(html, key, value !== undefined ? value : ""));
389
+ pushTask(`${keys.length ? keys.map(k => `_$HY.unset("${k}");`) : ""}_$HY.set("${key}",${error ? serializeError(error) : "null"})`);
390
+ } else {
391
+ buffer.write(`<div hidden id="${key}">${value !== undefined ? value : " "}</div>`);
392
+ pushTask(`${keys.length ? keys.map(k => `_$HY.unset("${k}")`).join(";") : ""}$df("${key}"${error ? "," + serializeError(error) : ""})${!scriptFlushed ? ";" + REPLACE_SCRIPT : ""}`);
393
+ scriptFlushed = true;
394
+ }
386
395
  }
387
396
  }
388
- checkEnd();
397
+ if (firstFlushed) checkEnd();
389
398
  return true;
390
399
  };
391
400
  }
392
401
  };
393
402
  let html = resolveSSRNode(escape(code()));
394
- html = injectAssets(sharedConfig.context.assets, html);
395
- Promise.resolve().then(() => {
403
+ function doShell() {
404
+ html = injectAssets(sharedConfig.context.assets, html);
396
405
  if (tasks.length) html = injectScripts(html, tasks.join(";"), nonce);
397
406
  buffer.write(html);
398
407
  tasks.length = 0;
@@ -402,29 +411,37 @@ function renderToStream(code, options = {}) {
402
411
  !completed && buffer.write(v);
403
412
  }
404
413
  });
405
- });
414
+ }
406
415
  return {
407
416
  pipe(w) {
408
- buffer = writable = w;
409
- tmp.forEach(chunk => buffer.write(chunk));
410
- if (completed) writable.end();else setTimeout(checkEnd);
417
+ Promise.allSettled(blockingResources).then(() => {
418
+ doShell();
419
+ buffer = writable = w;
420
+ tmp.forEach(chunk => buffer.write(chunk));
421
+ firstFlushed = true;
422
+ if (completed) writable.end();else setTimeout(checkEnd);
423
+ });
411
424
  },
412
425
  pipeTo(w) {
413
- const encoder = new TextEncoder();
414
- const writer = w.getWriter();
415
- writable = {
416
- end() {
417
- writer.releaseLock();
418
- w.close();
419
- }
420
- };
421
- buffer = {
422
- write(payload) {
423
- writer.write(encoder.encode(payload));
424
- }
425
- };
426
- tmp.forEach(chunk => buffer.write(chunk));
427
- if (completed) writable.end();else setTimeout(checkEnd);
426
+ Promise.allSettled(blockingResources).then(() => {
427
+ doShell();
428
+ const encoder = new TextEncoder();
429
+ const writer = w.getWriter();
430
+ writable = {
431
+ end() {
432
+ writer.releaseLock();
433
+ w.close();
434
+ }
435
+ };
436
+ buffer = {
437
+ write(payload) {
438
+ writer.write(encoder.encode(payload));
439
+ }
440
+ };
441
+ tmp.forEach(chunk => buffer.write(chunk));
442
+ firstFlushed = true;
443
+ if (completed) writable.end();else setTimeout(checkEnd);
444
+ });
428
445
  }
429
446
  };
430
447
  }
@@ -635,9 +652,26 @@ function waitForFragments(registry, key) {
635
652
  }
636
653
  function serializeSet(registry, key, value) {
637
654
  const exist = registry.get(value);
638
- if (exist) return `_$HY.set("${key}", _$HY.r["${exist}"][0]);`;
655
+ if (exist) return `_$HY.set("${key}", _$HY.r["${exist}"][0])`;
639
656
  value !== null && typeof value === "object" && registry.set(value, key);
640
- return `_$HY.set("${key}", ${devalue(value)});`;
657
+ return `_$HY.set("${key}", ${devalue(value)})`;
658
+ }
659
+ function replacePlaceholder(html, key, value) {
660
+ const nextRegex = /(<[/]?span[^>]*>)/g;
661
+ const marker = `<span id="pl-${key}">`;
662
+ const first = html.indexOf(marker);
663
+ if (first === -1) return html;
664
+ nextRegex.lastIndex = first + marker.length;
665
+ let match;
666
+ let open = 0,
667
+ close = 0;
668
+ while (match = nextRegex.exec(html)) {
669
+ if (match[0][1] === "/") {
670
+ close++;
671
+ if (close > open) break;
672
+ } else open++;
673
+ }
674
+ return html.slice(0, first) + value + html.slice(nextRegex.lastIndex);
641
675
  }
642
676
  function pipeToNodeWritable(code, writable, options = {}) {
643
677
  if (options.onReady) {