@solidjs/web 2.0.0-experimental.13 → 2.0.0-experimental.15

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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createMemo, sharedConfig, createRoot, ssrHandleError, omit } from 'solid-js';
2
- export { ErrorBoundary, For, Match, Repeat, Show, Suspense, Switch, createComponent, createRenderEffect as effect, getOwner, ssrRunInScope, untrack } from 'solid-js';
3
- import { Feature, Serializer, getCrossReferenceHeader } from 'seroval';
2
+ export { Errored, For, Loading, Match, Repeat, Show, Switch, createComponent, createRenderEffect as effect, getOwner, ssrRunInScope, untrack } from 'solid-js';
3
+ import { Serializer, Feature, getCrossReferenceHeader } from 'seroval';
4
4
  import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
5
5
 
6
6
  const Properties = /*#__PURE__*/new Set([
@@ -29,13 +29,16 @@ function createSerializer({
29
29
  onData,
30
30
  onDone,
31
31
  scopeId,
32
- onError
32
+ onError,
33
+ plugins: customPlugins
33
34
  }) {
35
+ const defaultPlugins = [AbortSignalPlugin,
36
+ CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
37
+ FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin];
38
+ const allPlugins = customPlugins ? [...customPlugins, ...defaultPlugins] : defaultPlugins;
34
39
  return new Serializer({
35
40
  scopeId,
36
- plugins: [AbortSignalPlugin,
37
- CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
38
- FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin],
41
+ plugins: allPlugins,
39
42
  globalIdentifier: GLOBAL_IDENTIFIER,
40
43
  disabledFeatures: ES2017FLAG,
41
44
  onData,
@@ -47,17 +50,102 @@ function getLocalHeaderScript(id) {
47
50
  return getCrossReferenceHeader(id) + ';';
48
51
  }
49
52
 
53
+ function resolveAssets(moduleUrl, manifest) {
54
+ if (!manifest) return null;
55
+ const entry = manifest[moduleUrl];
56
+ if (!entry) return null;
57
+ const css = [];
58
+ const js = [];
59
+ const visited = new Set();
60
+ const walk = key => {
61
+ if (visited.has(key)) return;
62
+ visited.add(key);
63
+ const e = manifest[key];
64
+ if (!e) return;
65
+ js.push(e.file);
66
+ if (e.css) for (let i = 0; i < e.css.length; i++) css.push(e.css[i]);
67
+ if (e.imports) for (let i = 0; i < e.imports.length; i++) walk(e.imports[i]);
68
+ };
69
+ walk(moduleUrl);
70
+ return {
71
+ js,
72
+ css
73
+ };
74
+ }
75
+ function registerEntryAssets(manifest) {
76
+ if (!manifest) return;
77
+ const ctx = sharedConfig.context;
78
+ if (!ctx?.registerAsset) return;
79
+ for (const key in manifest) {
80
+ if (manifest[key].isEntry) {
81
+ const assets = resolveAssets(key, manifest);
82
+ if (assets) {
83
+ for (let i = 0; i < assets.css.length; i++) ctx.registerAsset("style", assets.css[i]);
84
+ }
85
+ return;
86
+ }
87
+ }
88
+ }
89
+ function createAssetTracking() {
90
+ const boundaryModules = new Map();
91
+ const boundaryStyles = new Map();
92
+ const emittedAssets = new Set();
93
+ let currentBoundaryId = null;
94
+ return {
95
+ boundaryModules,
96
+ boundaryStyles,
97
+ emittedAssets,
98
+ get currentBoundaryId() {
99
+ return currentBoundaryId;
100
+ },
101
+ set currentBoundaryId(v) {
102
+ currentBoundaryId = v;
103
+ },
104
+ registerModule(moduleUrl, entryUrl) {
105
+ if (!currentBoundaryId) return;
106
+ let map = boundaryModules.get(currentBoundaryId);
107
+ if (!map) {
108
+ map = {};
109
+ boundaryModules.set(currentBoundaryId, map);
110
+ }
111
+ map[moduleUrl] = entryUrl;
112
+ },
113
+ getBoundaryModules(id) {
114
+ return boundaryModules.get(id) || null;
115
+ },
116
+ getBoundaryStyles(id) {
117
+ return boundaryStyles.get(id) || null;
118
+ }
119
+ };
120
+ }
121
+ function applyAssetTracking(context, tracking, manifest) {
122
+ Object.defineProperty(context, "_currentBoundaryId", {
123
+ get() {
124
+ return tracking.currentBoundaryId;
125
+ },
126
+ set(v) {
127
+ tracking.currentBoundaryId = v;
128
+ },
129
+ configurable: true,
130
+ enumerable: true
131
+ });
132
+ context.registerModule = tracking.registerModule;
133
+ context.getBoundaryModules = tracking.getBoundaryModules;
134
+ if (manifest) context.resolveAssets = moduleUrl => resolveAssets(moduleUrl, manifest);
135
+ }
50
136
  const VOID_ELEMENTS = /^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i;
51
- const REPLACE_SCRIPT = `function $df(e,n,o,t){if(n=document.getElementById(e),o=document.getElementById("pl-"+e)){for(;o&&8!==o.nodeType&&o.nodeValue!=="pl-"+e;)t=o.nextSibling,o.remove(),o=t;_$HY.done?o.remove():o.replaceWith(n.content)}n.remove(),_$HY.fe(e)}`;
137
+ const REPLACE_SCRIPT = `function $df(e,n,o,t){if(n=document.getElementById(e),o=document.getElementById("pl-"+e)){for(;o&&8!==o.nodeType&&o.nodeValue!=="pl-"+e;)t=o.nextSibling,o.remove(),o=t;_$HY.done?o.remove():o.replaceWith(n.content)}n.remove(),_$HY.fe(e)}function $dfs(e,c){(_$HY.sc=_$HY.sc||{})[e]=c}function $dfc(e){if(--_$HY.sc[e]<=0)delete _$HY.sc[e],$df(e)}`;
52
138
  function renderToString(code, options = {}) {
53
139
  const {
54
140
  renderId = "",
55
141
  nonce,
56
- noScripts
142
+ noScripts,
143
+ manifest
57
144
  } = options;
58
145
  let scripts = "";
59
146
  const serializer = createSerializer({
60
147
  scopeId: renderId,
148
+ plugins: options.plugins,
61
149
  onData(script) {
62
150
  if (noScripts) return;
63
151
  if (!scripts) {
@@ -67,6 +155,7 @@ function renderToString(code, options = {}) {
67
155
  },
68
156
  onError: options.onError
69
157
  });
158
+ const tracking = createAssetTracking();
70
159
  sharedConfig.context = {
71
160
  assets: [],
72
161
  nonce,
@@ -74,9 +163,26 @@ function renderToString(code, options = {}) {
74
163
  resolve: resolveSSRNode,
75
164
  ssr: ssr,
76
165
  serialize(id, p) {
77
- !sharedConfig.context.noHydrate && serializer.write(id, p);
166
+ if (sharedConfig.context.noHydrate) return;
167
+ if (p != null && typeof p === "object" && (typeof p.then === "function" || typeof p[Symbol.asyncIterator] === "function")) {
168
+ throw new Error("Cannot serialize async value in renderToString (id: " + id + "). " + "Use renderToStream for async data.");
169
+ }
170
+ serializer.write(id, p);
171
+ },
172
+ registerAsset(type, url) {
173
+ if (tracking.currentBoundaryId && type === "style") {
174
+ let styles = tracking.boundaryStyles.get(tracking.currentBoundaryId);
175
+ if (!styles) {
176
+ styles = new Set();
177
+ tracking.boundaryStyles.set(tracking.currentBoundaryId, styles);
178
+ }
179
+ styles.add(url);
180
+ }
181
+ tracking.emittedAssets.add(url);
78
182
  }
79
183
  };
184
+ applyAssetTracking(sharedConfig.context, tracking, manifest);
185
+ registerEntryAssets(manifest);
80
186
  let html = createRoot(d => {
81
187
  setTimeout(d);
82
188
  return resolveSSRSync(escape(code()));
@@ -86,6 +192,7 @@ function renderToString(code, options = {}) {
86
192
  sharedConfig.context.noHydrate = true;
87
193
  serializer.close();
88
194
  html = injectAssets(sharedConfig.context.assets, html);
195
+ html = injectPreloadLinks(tracking.emittedAssets, html);
89
196
  if (scripts.length) html = injectScripts(html, scripts, options.nonce);
90
197
  return html;
91
198
  }
@@ -95,10 +202,11 @@ function renderToStream(code, options = {}) {
95
202
  onCompleteShell,
96
203
  onCompleteAll,
97
204
  renderId = "",
98
- noScripts
205
+ noScripts,
206
+ manifest
99
207
  } = options;
100
208
  let dispose;
101
- const blockingPromises = [];
209
+ const blockingPromises = new Set();
102
210
  const pushTask = task => {
103
211
  if (noScripts) return;
104
212
  if (!tasks && !firstFlushed) {
@@ -123,6 +231,7 @@ function renderToStream(code, options = {}) {
123
231
  };
124
232
  const serializer = createSerializer({
125
233
  scopeId: options.renderId,
234
+ plugins: options.plugins,
126
235
  onData: pushTask,
127
236
  onDone,
128
237
  onError: options.onError
@@ -149,18 +258,38 @@ function renderToStream(code, options = {}) {
149
258
  let completed = false;
150
259
  let shellCompleted = false;
151
260
  let scriptFlushed = false;
261
+ let headStyles;
152
262
  let timer = null;
263
+ let rootHoles = null;
264
+ let nextHoleId = 0;
153
265
  let buffer = {
154
266
  write(payload) {
155
267
  tmp += payload;
156
268
  }
157
269
  };
270
+ const tracking = createAssetTracking();
158
271
  sharedConfig.context = context = {
159
272
  async: true,
160
273
  assets: [],
161
274
  nonce,
275
+ registerAsset(type, url) {
276
+ if (tracking.currentBoundaryId && type === "style") {
277
+ let styles = tracking.boundaryStyles.get(tracking.currentBoundaryId);
278
+ if (!styles) {
279
+ styles = new Set();
280
+ tracking.boundaryStyles.set(tracking.currentBoundaryId, styles);
281
+ }
282
+ styles.add(url);
283
+ }
284
+ if (!tracking.emittedAssets.has(url)) {
285
+ tracking.emittedAssets.add(url);
286
+ if (firstFlushed && type === "module") {
287
+ buffer.write(`<link rel="modulepreload" href="${url}">`);
288
+ }
289
+ }
290
+ },
162
291
  block(p) {
163
- if (!firstFlushed) blockingPromises.push(p);
292
+ if (!firstFlushed) blockingPromises.add(p);
164
293
  },
165
294
  replace(id, payloadFn) {
166
295
  if (firstFlushed) return;
@@ -170,16 +299,12 @@ function renderToStream(code, options = {}) {
170
299
  const last = html.indexOf(`<!--!$/${id}-->`, first + placeholder.length);
171
300
  html = html.slice(0, first) + resolveSSRSync(escape(payloadFn())) + html.slice(last + placeholder.length + 1);
172
301
  },
173
- serialize(id, p, wait) {
174
- const serverOnly = sharedConfig.context.noHydrate;
175
- if (!firstFlushed && wait && typeof p === "object" && "then" in p) {
176
- blockingPromises.push(p);
177
- !serverOnly && p.then(d => {
178
- serializer.write(id, d);
179
- }).catch(e => {
180
- serializer.write(id, e);
181
- });
182
- } else if (!serverOnly) serializer.write(id, p);
302
+ serialize(id, p, deferStream) {
303
+ if (sharedConfig.context.noHydrate) return;
304
+ if (!firstFlushed && deferStream && typeof p === "object" && "then" in p) {
305
+ blockingPromises.add(p);
306
+ p.then(d => serializer.write(id, d)).catch(e => serializer.write(id, e));
307
+ } else serializer.write(id, p);
183
308
  },
184
309
  escape: escape,
185
310
  resolve: resolveSSRNode,
@@ -210,18 +335,33 @@ function renderToStream(code, options = {}) {
210
335
  const parent = registry.get(parentKey);
211
336
  parent.children ||= {};
212
337
  parent.children[key] = value !== undefined ? value : "";
338
+ serializeFragmentAssets(key, tracking.boundaryModules, context);
339
+ propagateBoundaryStyles(key, parentKey, tracking);
213
340
  item.resolve();
214
341
  return;
215
342
  }
216
343
  if (!completed) {
217
344
  if (!firstFlushed) {
218
345
  queue(() => html = replacePlaceholder(html, key, value !== undefined ? value : ""));
346
+ serializeFragmentAssets(key, tracking.boundaryModules, context);
219
347
  item.resolve(error);
220
348
  } else {
221
- buffer.write(`<template id="${key}">${value !== undefined ? value : " "}</template>`);
222
- pushTask(`$df("${key}")${!scriptFlushed ? ";" + REPLACE_SCRIPT : ""}`);
349
+ serializeFragmentAssets(key, tracking.boundaryModules, context);
350
+ const styles = collectStreamStyles(key, tracking, headStyles);
351
+ if (styles.length) {
352
+ pushTask(`$dfs("${key}",${styles.length})${!scriptFlushed ? ";" + REPLACE_SCRIPT : ""}`);
353
+ scriptFlushed = true;
354
+ writeTasks();
355
+ for (const url of styles) {
356
+ buffer.write(`<link rel="stylesheet" href="${url}" onload="$dfc('${key}')" onerror="$dfc('${key}')">`);
357
+ }
358
+ buffer.write(`<template id="${key}">${value !== undefined ? value : " "}</template>`);
359
+ } else {
360
+ buffer.write(`<template id="${key}">${value !== undefined ? value : " "}</template>`);
361
+ pushTask(`$df("${key}")${!scriptFlushed ? ";" + REPLACE_SCRIPT : ""}`);
362
+ scriptFlushed = true;
363
+ }
223
364
  item.resolve(error);
224
- scriptFlushed = true;
225
365
  }
226
366
  }
227
367
  }
@@ -229,16 +369,47 @@ function renderToStream(code, options = {}) {
229
369
  };
230
370
  }
231
371
  };
372
+ applyAssetTracking(context, tracking, manifest);
373
+ registerEntryAssets(manifest);
232
374
  let html = createRoot(d => {
233
375
  dispose = d;
234
- return resolveSSRSync(escape(code()));
376
+ const res = resolveSSRNode(escape(code()));
377
+ if (!res.h.length) return res.t[0];
378
+ rootHoles = [];
379
+ let out = res.t[0];
380
+ for (let i = 0; i < res.h.length; i++) {
381
+ const id = nextHoleId++;
382
+ rootHoles.push({
383
+ id,
384
+ fn: res.h[i]
385
+ });
386
+ out += `<!--rh${id}-->` + res.t[i + 1];
387
+ }
388
+ for (const p of res.p) blockingPromises.add(p);
389
+ return out;
235
390
  }, {
236
391
  id: renderId
237
392
  });
238
393
  function doShell() {
239
394
  if (shellCompleted) return;
395
+ if (rootHoles) {
396
+ for (const {
397
+ id,
398
+ fn
399
+ } of rootHoles) {
400
+ const marker = `<!--rh${id}-->`;
401
+ const res = resolveSSRNode(fn);
402
+ html = html.replace(marker, !res.h.length ? res.t[0] : "");
403
+ }
404
+ rootHoles = null;
405
+ }
240
406
  sharedConfig.context = context;
241
407
  html = injectAssets(context.assets, html);
408
+ headStyles = new Set();
409
+ for (const url of tracking.emittedAssets) {
410
+ if (url.endsWith(".css")) headStyles.add(url);
411
+ }
412
+ html = injectPreloadLinks(tracking.emittedAssets, html);
242
413
  if (tasks.length) html = injectScripts(html, tasks, nonce);
243
414
  buffer.write(html);
244
415
  tasks = "";
@@ -289,13 +460,13 @@ function renderToStream(code, options = {}) {
289
460
  writable = {
290
461
  end() {
291
462
  writer.releaseLock();
292
- w.close();
463
+ w.close().catch(() => {});
293
464
  resolve();
294
465
  }
295
466
  };
296
467
  buffer = {
297
468
  write(payload) {
298
- writer.write(encoder.encode(payload));
469
+ writer.write(encoder.encode(payload)).catch(() => {});
299
470
  }
300
471
  };
301
472
  buffer.write(tmp);
@@ -513,9 +684,9 @@ function queue(fn) {
513
684
  return Promise.resolve().then(fn);
514
685
  }
515
686
  function allSettled(promises) {
516
- let length = promises.length;
687
+ let size = promises.size;
517
688
  return Promise.allSettled(promises).then(() => {
518
- if (promises.length !== length) return allSettled(promises);
689
+ if (promises.size !== size) return allSettled(promises);
519
690
  return;
520
691
  });
521
692
  }
@@ -527,6 +698,48 @@ function injectAssets(assets, html) {
527
698
  if (index === -1) return html;
528
699
  return html.slice(0, index) + out + html.slice(index);
529
700
  }
701
+ function injectPreloadLinks(emittedAssets, html, nonce) {
702
+ if (!emittedAssets.size) return html;
703
+ let links = "";
704
+ for (const url of emittedAssets) {
705
+ if (url.endsWith(".css")) {
706
+ links += `<link rel="stylesheet" href="${url}">`;
707
+ } else {
708
+ links += `<link rel="modulepreload" href="${url}">`;
709
+ }
710
+ }
711
+ const index = html.indexOf("</head>");
712
+ if (index === -1) return html;
713
+ return html.slice(0, index) + links + html.slice(index);
714
+ }
715
+ function serializeFragmentAssets(key, boundaryModules, context) {
716
+ const map = boundaryModules.get(key);
717
+ if (!map || !Object.keys(map).length) return;
718
+ context.serialize(key + "_assets", map);
719
+ }
720
+ function propagateBoundaryStyles(childKey, parentKey, tracking) {
721
+ const childStyles = tracking.getBoundaryStyles(childKey);
722
+ if (!childStyles) return;
723
+ let parentStyles = tracking.boundaryStyles.get(parentKey);
724
+ if (!parentStyles) {
725
+ parentStyles = new Set();
726
+ tracking.boundaryStyles.set(parentKey, parentStyles);
727
+ }
728
+ for (const url of childStyles) {
729
+ parentStyles.add(url);
730
+ }
731
+ }
732
+ function collectStreamStyles(key, tracking, headStyles) {
733
+ const styles = tracking.getBoundaryStyles(key);
734
+ if (!styles) return [];
735
+ const result = [];
736
+ for (const url of styles) {
737
+ if (!headStyles || !headStyles.has(url)) {
738
+ result.push(url);
739
+ }
740
+ }
741
+ return result;
742
+ }
530
743
  function injectScripts(html, scripts, nonce) {
531
744
  const tag = `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>`;
532
745
  const index = html.indexOf("<!--xs-->");
@@ -617,14 +830,14 @@ function resolveSSRNode(node, result = {
617
830
  function resolveSSRSync(node) {
618
831
  const res = resolveSSRNode(node);
619
832
  if (!res.h.length) return res.t[0];
620
- throw new Error("This value cannot be rendered synchronously. Are you missing a Suspsense boundary?");
833
+ throw new Error("This value cannot be rendered synchronously. Are you missing a boundary?");
621
834
  }
622
835
  const RequestContext = Symbol();
623
836
  function getRequestEvent() {
624
837
  return globalThis[RequestContext] ? globalThis[RequestContext].getStore() || sharedConfig.context && sharedConfig.context.event || console.log("RequestEvent is missing. This is most likely due to accessing `getRequestEvent` non-managed async scope in a partially polyfilled environment. Try moving it above all `await` calls.") : undefined;
625
838
  }
626
839
  function renderToStringAsync(code, options = {}) {
627
- return renderToStream(code, options).then(html => html);
840
+ return new Promise(resolve => renderToStream(code, options).then(resolve));
628
841
  }
629
842
  function notSup() {
630
843
  throw new Error("Client-only API called on the server side. Run client-only code in onMount, or conditionally run client-only component with <Show>.");
package/dist/web.cjs CHANGED
@@ -226,6 +226,13 @@ function use(fn, element, arg) {
226
226
  function insert(parent, accessor, marker, initial) {
227
227
  const multi = marker !== undefined;
228
228
  if (multi && !initial) initial = [];
229
+ if (isHydrating(parent) && Array.isArray(initial)) {
230
+ let j = 0;
231
+ for (let i = 0; i < initial.length; i++) {
232
+ if (initial[i].nodeType === 8 && initial[i].nodeValue === "!$") initial[i].remove();else initial[j++] = initial[i];
233
+ }
234
+ initial.length = j;
235
+ }
229
236
  if (typeof accessor !== "function") {
230
237
  accessor = normalize(accessor, initial, multi, true);
231
238
  if (typeof accessor !== "function") return insertExpression(parent, accessor, initial, marker);
@@ -252,11 +259,29 @@ function assign(node, props, isSVG, skipChildren, prevProps = {}, skipRef = fals
252
259
  function hydrate$1(code, element, options = {}) {
253
260
  if (globalThis._$HY.done) return render(code, element, [...element.childNodes], options);
254
261
  options.renderId ||= "";
262
+ if (!globalThis._$HY.modules) globalThis._$HY.modules = {};
263
+ if (!globalThis._$HY.loading) globalThis._$HY.loading = {};
255
264
  solidJs.sharedConfig.completed = globalThis._$HY.completed;
256
265
  solidJs.sharedConfig.events = globalThis._$HY.events;
257
266
  solidJs.sharedConfig.load = id => globalThis._$HY.r[id];
258
267
  solidJs.sharedConfig.has = id => id in globalThis._$HY.r;
259
268
  solidJs.sharedConfig.gather = root => gatherHydratable(element, root);
269
+ solidJs.sharedConfig.cleanupFragment = id => {
270
+ const tpl = document.getElementById("pl-" + id);
271
+ if (tpl) {
272
+ let node = tpl.nextSibling;
273
+ while (node) {
274
+ const next = node.nextSibling;
275
+ if (node.nodeType === 8 && node.nodeValue === "pl-" + id) {
276
+ node.remove();
277
+ break;
278
+ }
279
+ node.remove();
280
+ node = next;
281
+ }
282
+ tpl.remove();
283
+ }
284
+ };
260
285
  solidJs.sharedConfig.registry = new Map();
261
286
  solidJs.sharedConfig.hydrating = true;
262
287
  try {
@@ -324,7 +349,7 @@ function runHydrationEvents() {
324
349
  }
325
350
  }
326
351
  function isHydrating(node) {
327
- return solidJs.sharedConfig.hydrating && !solidJs.sharedConfig.done && (!node || node.isConnected);
352
+ return solidJs.sharedConfig.hydrating && (!node || node.isConnected);
328
353
  }
329
354
  function toggleClassKey(node, key, value) {
330
355
  const classNames = key.trim().split(/\s+/);
@@ -406,7 +431,6 @@ function eventHandler(e) {
406
431
  return node || document;
407
432
  }
408
433
  });
409
- if (solidJs.sharedConfig.registry && !solidJs.sharedConfig.done) solidJs.sharedConfig.done = _$HY.done = true;
410
434
  if (e.composedPath) {
411
435
  const path = e.composedPath();
412
436
  retarget(path[0]);
package/dist/web.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createMemo, createRoot, flatten, untrack, createRenderEffect, sharedConfig, enableHydration, omit } from 'solid-js';
1
+ import { createMemo, sharedConfig, createRenderEffect, createRoot, flatten, untrack, omit, enableHydration } from 'solid-js';
2
2
  export { Errored, For, Loading, Match, Show, Switch, createComponent, createRenderEffect as effect, getOwner, merge as mergeProps, untrack } from 'solid-js';
3
3
 
4
4
  const Properties = /*#__PURE__*/new Set([
@@ -225,6 +225,13 @@ function use(fn, element, arg) {
225
225
  function insert(parent, accessor, marker, initial) {
226
226
  const multi = marker !== undefined;
227
227
  if (multi && !initial) initial = [];
228
+ if (isHydrating(parent) && Array.isArray(initial)) {
229
+ let j = 0;
230
+ for (let i = 0; i < initial.length; i++) {
231
+ if (initial[i].nodeType === 8 && initial[i].nodeValue === "!$") initial[i].remove();else initial[j++] = initial[i];
232
+ }
233
+ initial.length = j;
234
+ }
228
235
  if (typeof accessor !== "function") {
229
236
  accessor = normalize(accessor, initial, multi, true);
230
237
  if (typeof accessor !== "function") return insertExpression(parent, accessor, initial, marker);
@@ -251,11 +258,29 @@ function assign(node, props, isSVG, skipChildren, prevProps = {}, skipRef = fals
251
258
  function hydrate$1(code, element, options = {}) {
252
259
  if (globalThis._$HY.done) return render(code, element, [...element.childNodes], options);
253
260
  options.renderId ||= "";
261
+ if (!globalThis._$HY.modules) globalThis._$HY.modules = {};
262
+ if (!globalThis._$HY.loading) globalThis._$HY.loading = {};
254
263
  sharedConfig.completed = globalThis._$HY.completed;
255
264
  sharedConfig.events = globalThis._$HY.events;
256
265
  sharedConfig.load = id => globalThis._$HY.r[id];
257
266
  sharedConfig.has = id => id in globalThis._$HY.r;
258
267
  sharedConfig.gather = root => gatherHydratable(element, root);
268
+ sharedConfig.cleanupFragment = id => {
269
+ const tpl = document.getElementById("pl-" + id);
270
+ if (tpl) {
271
+ let node = tpl.nextSibling;
272
+ while (node) {
273
+ const next = node.nextSibling;
274
+ if (node.nodeType === 8 && node.nodeValue === "pl-" + id) {
275
+ node.remove();
276
+ break;
277
+ }
278
+ node.remove();
279
+ node = next;
280
+ }
281
+ tpl.remove();
282
+ }
283
+ };
259
284
  sharedConfig.registry = new Map();
260
285
  sharedConfig.hydrating = true;
261
286
  try {
@@ -323,7 +348,7 @@ function runHydrationEvents() {
323
348
  }
324
349
  }
325
350
  function isHydrating(node) {
326
- return sharedConfig.hydrating && !sharedConfig.done && (!node || node.isConnected);
351
+ return sharedConfig.hydrating && (!node || node.isConnected);
327
352
  }
328
353
  function toggleClassKey(node, key, value) {
329
354
  const classNames = key.trim().split(/\s+/);
@@ -405,7 +430,6 @@ function eventHandler(e) {
405
430
  return node || document;
406
431
  }
407
432
  });
408
- if (sharedConfig.registry && !sharedConfig.done) sharedConfig.done = _$HY.done = true;
409
433
  if (e.composedPath) {
410
434
  const path = e.composedPath();
411
435
  retarget(path[0]);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@solidjs/web",
3
3
  "description": "Solid's web runtime for the browser and the server",
4
- "version": "2.0.0-experimental.13",
4
+ "version": "2.0.0-experimental.15",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
7
7
  "homepage": "https://solidjs.com",
@@ -75,10 +75,10 @@
75
75
  "seroval-plugins": "^1.1.0"
76
76
  },
77
77
  "peerDependencies": {
78
- "solid-js": "^2.0.0-experimental.13"
78
+ "solid-js": "^2.0.0-experimental.15"
79
79
  },
80
80
  "devDependencies": {
81
- "solid-js": "2.0.0-experimental.13"
81
+ "solid-js": "2.0.0-experimental.15"
82
82
  },
83
83
  "scripts": {
84
84
  "build": "npm-run-all -nl build:*",
@@ -90,7 +90,8 @@
90
90
  "types:web": "tsc --project ./tsconfig.build.json",
91
91
  "types:copy-web": "ncp ../../node_modules/dom-expressions/src/client.d.ts ./types/client.d.ts && ncp ../../node_modules/dom-expressions/src/server.d.ts ./types/server.d.ts",
92
92
  "types:web-storage": "tsc --project ./storage/tsconfig.build.json",
93
- "test": "vitest run",
93
+ "test": "vitest run && vitest run --config vite.config.server.mjs",
94
+ "test:server": "vitest run --config vite.config.server.mjs",
94
95
  "coverage": "vitest run --coverage",
95
96
  "test-types": "tsc --project tsconfig.test.json"
96
97
  }
@@ -0,0 +1 @@
1
+ export * from "dom-expressions/src/client.js";
@@ -0,0 +1,45 @@
1
+ import { hydrate as hydrateCore } from "./client.js";
2
+ import { JSX, ComponentProps, ValidComponent } from "solid-js";
3
+ export * from "./client.js";
4
+ export { For, Show, Switch, Match, Errored, Loading, merge as mergeProps } from "solid-js";
5
+ export * from "./server-mock.js";
6
+ export declare const isServer: boolean;
7
+ export declare const isDev: boolean;
8
+ export declare const hydrate: typeof hydrateCore;
9
+ /**
10
+ * Renders components somewhere else in the DOM
11
+ *
12
+ * Useful for inserting modals and tooltips outside of an cropping layout. If no mount point is given, the portal is inserted in document.body; it is wrapped in a `<div>` unless the target is document.head or `isSVG` is true. setting `useShadow` to true places the element in a shadow root to isolate styles.
13
+ *
14
+ * @description https://docs.solidjs.com/reference/components/portal
15
+ */
16
+ export declare function Portal<T extends boolean = false, S extends boolean = false>(props: {
17
+ mount?: Element;
18
+ children: JSX.Element;
19
+ }): Text;
20
+ export type DynamicProps<T extends ValidComponent, P = ComponentProps<T>> = {
21
+ [K in keyof P]: P[K];
22
+ } & {
23
+ component: T | undefined;
24
+ };
25
+ /**
26
+ * Renders an arbitrary component or element with the given props
27
+ *
28
+ * This is a lower level version of the `Dynamic` component, useful for
29
+ * performance optimizations in libraries. Do not use this unless you know
30
+ * what you are doing.
31
+ * ```typescript
32
+ * const element = () => multiline() ? 'textarea' : 'input';
33
+ * createDynamic(element, { value: value() });
34
+ * ```
35
+ * @description https://docs.solidjs.com/reference/components/dynamic
36
+ */
37
+ export declare function createDynamic<T extends ValidComponent>(component: () => T | undefined, props: ComponentProps<T>): JSX.Element;
38
+ /**
39
+ * Renders an arbitrary custom or native component and passes the other props
40
+ * ```typescript
41
+ * <Dynamic component={multiline() ? 'textarea' : 'input'} value={value()} />
42
+ * ```
43
+ * @description https://docs.solidjs.com/reference/components/dynamic
44
+ */
45
+ export declare function Dynamic<T extends ValidComponent>(props: DynamicProps<T>): JSX.Element;