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

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/dev.cjs CHANGED
@@ -1228,17 +1228,16 @@ function enableHydration() {
1228
1228
  hydrationEnabled = true;
1229
1229
  }
1230
1230
  function createComponent(Comp, props) {
1231
- if (props == null || typeof props !== "object") props = {};
1232
1231
  if (hydrationEnabled) {
1233
1232
  if (sharedConfig.context) {
1234
1233
  const c = sharedConfig.context;
1235
1234
  setHydrateContext(nextHydrateContext());
1236
- const r = devComponent(Comp, props) ;
1235
+ const r = devComponent(Comp, props || {}) ;
1237
1236
  setHydrateContext(c);
1238
1237
  return r;
1239
1238
  }
1240
1239
  }
1241
- return devComponent(Comp, props);
1240
+ return devComponent(Comp, props || {});
1242
1241
  }
1243
1242
  function trueFn() {
1244
1243
  return true;
@@ -1269,7 +1268,7 @@ const propTraps = {
1269
1268
  }
1270
1269
  };
1271
1270
  function resolveSource(s) {
1272
- return (s = typeof s === "function" ? s() : s) == null || typeof s !== "object" ? {} : s;
1271
+ return (s = typeof s === "function" ? s() : s) == null ? {} : s;
1273
1272
  }
1274
1273
  function mergeProps(...sources) {
1275
1274
  return new Proxy({
package/dist/dev.js CHANGED
@@ -1224,17 +1224,16 @@ function enableHydration() {
1224
1224
  hydrationEnabled = true;
1225
1225
  }
1226
1226
  function createComponent(Comp, props) {
1227
- if (props == null || typeof props !== "object") props = {};
1228
1227
  if (hydrationEnabled) {
1229
1228
  if (sharedConfig.context) {
1230
1229
  const c = sharedConfig.context;
1231
1230
  setHydrateContext(nextHydrateContext());
1232
- const r = devComponent(Comp, props) ;
1231
+ const r = devComponent(Comp, props || {}) ;
1233
1232
  setHydrateContext(c);
1234
1233
  return r;
1235
1234
  }
1236
1235
  }
1237
- return devComponent(Comp, props);
1236
+ return devComponent(Comp, props || {});
1238
1237
  }
1239
1238
  function trueFn() {
1240
1239
  return true;
@@ -1265,7 +1264,7 @@ const propTraps = {
1265
1264
  }
1266
1265
  };
1267
1266
  function resolveSource(s) {
1268
- return (s = typeof s === "function" ? s() : s) == null || typeof s !== "object" ? {} : s;
1267
+ return (s = typeof s === "function" ? s() : s) == null ? {} : s;
1269
1268
  }
1270
1269
  function mergeProps(...sources) {
1271
1270
  return new Proxy({
package/dist/server.cjs CHANGED
@@ -246,15 +246,14 @@ function createUniqueId() {
246
246
  return `${ctx.id}${ctx.count++}`;
247
247
  }
248
248
  function createComponent(Comp, props) {
249
- if (props == null || typeof props !== "object") props = {};
250
249
  if (sharedConfig.context && !sharedConfig.context.noHydrate) {
251
250
  const c = sharedConfig.context;
252
251
  setHydrateContext(nextHydrateContext());
253
- const r = Comp(props);
252
+ const r = Comp(props || {});
254
253
  setHydrateContext(c);
255
254
  return r;
256
255
  }
257
- return Comp(props);
256
+ return Comp(props || {});
258
257
  }
259
258
  function mergeProps(...sources) {
260
259
  const target = {};
@@ -401,7 +400,7 @@ function createResource(source, fetcher, options = {}) {
401
400
  }
402
401
  if (p && "then" in p) {
403
402
  read.loading = true;
404
- if (ctx.writeResource) ctx.writeResource(id, p);
403
+ if (ctx.writeResource) ctx.writeResource(id, p, undefined, options.deferStream);
405
404
  return p.then(res => {
406
405
  read.loading = false;
407
406
  ctx.resources[id].data = res;
package/dist/server.js CHANGED
@@ -242,15 +242,14 @@ function createUniqueId() {
242
242
  return `${ctx.id}${ctx.count++}`;
243
243
  }
244
244
  function createComponent(Comp, props) {
245
- if (props == null || typeof props !== "object") props = {};
246
245
  if (sharedConfig.context && !sharedConfig.context.noHydrate) {
247
246
  const c = sharedConfig.context;
248
247
  setHydrateContext(nextHydrateContext());
249
- const r = Comp(props);
248
+ const r = Comp(props || {});
250
249
  setHydrateContext(c);
251
250
  return r;
252
251
  }
253
- return Comp(props);
252
+ return Comp(props || {});
254
253
  }
255
254
  function mergeProps(...sources) {
256
255
  const target = {};
@@ -397,7 +396,7 @@ function createResource(source, fetcher, options = {}) {
397
396
  }
398
397
  if (p && "then" in p) {
399
398
  read.loading = true;
400
- if (ctx.writeResource) ctx.writeResource(id, p);
399
+ if (ctx.writeResource) ctx.writeResource(id, p, undefined, options.deferStream);
401
400
  return p.then(res => {
402
401
  read.loading = false;
403
402
  ctx.resources[id].data = res;
package/dist/solid.cjs CHANGED
@@ -1147,17 +1147,16 @@ function enableHydration() {
1147
1147
  hydrationEnabled = true;
1148
1148
  }
1149
1149
  function createComponent(Comp, props) {
1150
- if (props == null || typeof props !== "object") props = {};
1151
1150
  if (hydrationEnabled) {
1152
1151
  if (sharedConfig.context) {
1153
1152
  const c = sharedConfig.context;
1154
1153
  setHydrateContext(nextHydrateContext());
1155
- const r = untrack(() => Comp(props));
1154
+ const r = untrack(() => Comp(props || {}));
1156
1155
  setHydrateContext(c);
1157
1156
  return r;
1158
1157
  }
1159
1158
  }
1160
- return untrack(() => Comp(props));
1159
+ return untrack(() => Comp(props || {}));
1161
1160
  }
1162
1161
  function trueFn() {
1163
1162
  return true;
@@ -1188,7 +1187,7 @@ const propTraps = {
1188
1187
  }
1189
1188
  };
1190
1189
  function resolveSource(s) {
1191
- return (s = typeof s === "function" ? s() : s) == null || typeof s !== "object" ? {} : s;
1190
+ return (s = typeof s === "function" ? s() : s) == null ? {} : s;
1192
1191
  }
1193
1192
  function mergeProps(...sources) {
1194
1193
  return new Proxy({
package/dist/solid.js CHANGED
@@ -1143,17 +1143,16 @@ function enableHydration() {
1143
1143
  hydrationEnabled = true;
1144
1144
  }
1145
1145
  function createComponent(Comp, props) {
1146
- if (props == null || typeof props !== "object") props = {};
1147
1146
  if (hydrationEnabled) {
1148
1147
  if (sharedConfig.context) {
1149
1148
  const c = sharedConfig.context;
1150
1149
  setHydrateContext(nextHydrateContext());
1151
- const r = untrack(() => Comp(props));
1150
+ const r = untrack(() => Comp(props || {}));
1152
1151
  setHydrateContext(c);
1153
1152
  return r;
1154
1153
  }
1155
1154
  }
1156
- return untrack(() => Comp(props));
1155
+ return untrack(() => Comp(props || {}));
1157
1156
  }
1158
1157
  function trueFn() {
1159
1158
  return true;
@@ -1184,7 +1183,7 @@ const propTraps = {
1184
1183
  }
1185
1184
  };
1186
1185
  function resolveSource(s) {
1187
- return (s = typeof s === "function" ? s() : s) == null || typeof s !== "object" ? {} : s;
1186
+ return (s = typeof s === "function" ? s() : s) == null ? {} : s;
1188
1187
  }
1189
1188
  function mergeProps(...sources) {
1190
1189
  return new Proxy({
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.2",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
7
7
  "homepage": "https://solidjs.com",
@@ -144,5 +144,5 @@
144
144
  "compiler",
145
145
  "performance"
146
146
  ],
147
- "gitHead": "34628200f7c8e0a329905688a455848096a3e429"
147
+ "gitHead": "40902779866f8006cc5460c6ff82dbadf85d3f0f"
148
148
  }
@@ -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) {