@solidjs/web 2.0.0-beta.16 → 2.0.0-beta.17

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
@@ -140,25 +140,48 @@ function createAssetTracking() {
140
140
  const boundaryModules = new Map();
141
141
  const boundaryStyles = new Map();
142
142
  const emittedAssets = new Set();
143
+ const inlineStyles = new Map();
143
144
  let currentBoundaryId = null;
144
145
  return {
145
146
  boundaryModules,
146
147
  boundaryStyles,
147
148
  emittedAssets,
149
+ inlineStyles,
150
+ registerInlineStyle(desc) {
151
+ let entry = inlineStyles.get(desc.id);
152
+ if (!entry) {
153
+ entry = {
154
+ id: desc.id,
155
+ content: desc.content || "",
156
+ attrs: desc.attrs,
157
+ emitted: false
158
+ };
159
+ inlineStyles.set(desc.id, entry);
160
+ }
161
+ if (currentBoundaryId) {
162
+ let styles = boundaryStyles.get(currentBoundaryId);
163
+ if (!styles) {
164
+ styles = new Set();
165
+ boundaryStyles.set(currentBoundaryId, styles);
166
+ }
167
+ styles.add(entry);
168
+ }
169
+ return entry;
170
+ },
148
171
  get currentBoundaryId() {
149
172
  return currentBoundaryId;
150
173
  },
151
174
  set currentBoundaryId(v) {
152
175
  currentBoundaryId = v;
153
176
  },
154
- registerModule(moduleUrl, entryUrl) {
177
+ registerModule(key, entryUrl) {
155
178
  const id = currentBoundaryId || "";
156
179
  let map = boundaryModules.get(id);
157
180
  if (!map) {
158
181
  map = {};
159
182
  boundaryModules.set(id, map);
160
183
  }
161
- map[moduleUrl] = entryUrl;
184
+ map[key] = entryUrl;
162
185
  },
163
186
  getBoundaryModules(id) {
164
187
  return boundaryModules.get(id) || null;
@@ -219,16 +242,20 @@ function renderToString(code, options = {}) {
219
242
  }
220
243
  serializer.write(id, p);
221
244
  },
222
- registerAsset(type, url) {
245
+ registerAsset(type, value) {
246
+ if (type === "inline-style") {
247
+ tracking.registerInlineStyle(value);
248
+ return;
249
+ }
223
250
  if (tracking.currentBoundaryId && type === "style") {
224
251
  let styles = tracking.boundaryStyles.get(tracking.currentBoundaryId);
225
252
  if (!styles) {
226
253
  styles = new Set();
227
254
  tracking.boundaryStyles.set(tracking.currentBoundaryId, styles);
228
255
  }
229
- styles.add(url);
256
+ styles.add(value);
230
257
  }
231
- tracking.emittedAssets.add(url);
258
+ tracking.emittedAssets.add(value);
232
259
  }
233
260
  };
234
261
  applyAssetTracking(sharedConfig.context, tracking, manifest);
@@ -244,6 +271,7 @@ function renderToString(code, options = {}) {
244
271
  serializer.close();
245
272
  html = injectAssets(sharedConfig.context.assets, html);
246
273
  html = injectPreloadLinks(tracking.emittedAssets, html);
274
+ html = injectInlineStyles(tracking.inlineStyles, html, nonce);
247
275
  if (scripts.length) html = injectScripts(html, scripts, options.nonce);
248
276
  return html;
249
277
  }
@@ -354,19 +382,27 @@ function renderToStream(code, options = {}) {
354
382
  async: true,
355
383
  assets: [],
356
384
  nonce,
357
- registerAsset(type, url) {
385
+ registerAsset(type, value) {
386
+ if (type === "inline-style") {
387
+ const entry = tracking.registerInlineStyle(value);
388
+ if (firstFlushed && !tracking.currentBoundaryId && !entry.emitted) {
389
+ entry.emitted = true;
390
+ buffer.write(renderInlineStyle(entry, nonce));
391
+ }
392
+ return;
393
+ }
358
394
  if (tracking.currentBoundaryId && type === "style") {
359
395
  let styles = tracking.boundaryStyles.get(tracking.currentBoundaryId);
360
396
  if (!styles) {
361
397
  styles = new Set();
362
398
  tracking.boundaryStyles.set(tracking.currentBoundaryId, styles);
363
399
  }
364
- styles.add(url);
400
+ styles.add(value);
365
401
  }
366
- if (!tracking.emittedAssets.has(url)) {
367
- tracking.emittedAssets.add(url);
402
+ if (!tracking.emittedAssets.has(value)) {
403
+ tracking.emittedAssets.add(value);
368
404
  if (firstFlushed && type === "module") {
369
- buffer.write(`<link rel="modulepreload" href="${url}">`);
405
+ buffer.write(`<link rel="modulepreload" href="${value}">`);
370
406
  }
371
407
  }
372
408
  },
@@ -450,10 +486,13 @@ function renderToStream(code, options = {}) {
450
486
  serializeFragmentAssets(key, tracking.boundaryModules, context);
451
487
  const styles = collectStreamStyles(key, tracking, headStyles);
452
488
  const deferActivation = !!revealGroup;
453
- if (styles.length) {
454
- emitTask(`$dfs("${key}",${styles.length},${deferActivation ? 1 : 0})`);
489
+ for (let i = 0; i < styles.inline.length; i++) {
490
+ buffer.write(renderInlineStyle(styles.inline[i], nonce));
491
+ }
492
+ if (styles.links.length) {
493
+ emitTask(`$dfs("${key}",${styles.links.length},${deferActivation ? 1 : 0})`);
455
494
  writeTasks();
456
- for (const url of styles) {
495
+ for (const url of styles.links) {
457
496
  buffer.write(`<link rel="stylesheet" href="${url}" onload="$dfc('${key}')" onerror="$dfc('${key}')">`);
458
497
  }
459
498
  buffer.write(`<template id="${key}">${value !== undefined ? value : " "}</template>`);
@@ -544,6 +583,7 @@ function renderToStream(code, options = {}) {
544
583
  if (url.endsWith(".css")) headStyles.add(url);
545
584
  }
546
585
  html = injectPreloadLinks(tracking.emittedAssets, html);
586
+ html = injectInlineStyles(tracking.inlineStyles, html, nonce);
547
587
  serializeRootAssets();
548
588
  if (tasks.length) html = injectScripts(html, tasks, nonce);
549
589
  buffer.write(html);
@@ -849,10 +889,11 @@ function ssrStyleProperty(name, value) {
849
889
  return value != null ? name + value : "";
850
890
  }
851
891
  function ssrElement(tag, props, children, needsId) {
892
+ const hk = needsId ? ssrHydrationKey() : "";
852
893
  if (props == null) props = {};else if (typeof props === "function") props = props();
853
894
  const skipChildren = VOID_ELEMENTS.test(tag);
854
895
  const keys = Object.keys(props);
855
- let result = `<${tag}${needsId ? ssrHydrationKey() : ""} `;
896
+ let result = `<${tag}${hk} `;
856
897
  for (let i = 0; i < keys.length; i++) {
857
898
  const prop = keys[i];
858
899
  if (ChildProperties.has(prop)) {
@@ -897,7 +938,10 @@ function escape(s, attr) {
897
938
  for (let i = 0; i < s.length; i++) s[i] = escape(s[i]);
898
939
  return s;
899
940
  }
900
- if (attr && t === "boolean") return s;
941
+ if (attr) {
942
+ if (s == null || t === "boolean" || t === "number") return s;
943
+ return escape(String(s), attr);
944
+ }
901
945
  return s;
902
946
  }
903
947
  const delimCode = attr ? 34 : 60;
@@ -1033,14 +1077,48 @@ function propagateBoundaryStyles(childKey, parentKey, tracking) {
1033
1077
  }
1034
1078
  function collectStreamStyles(key, tracking, headStyles) {
1035
1079
  const styles = tracking.getBoundaryStyles(key);
1036
- if (!styles) return [];
1037
- const result = [];
1038
- for (const url of styles) {
1039
- if (!headStyles || !headStyles.has(url)) {
1040
- result.push(url);
1080
+ const links = [];
1081
+ const inline = [];
1082
+ if (!styles) return {
1083
+ links,
1084
+ inline
1085
+ };
1086
+ for (const entry of styles) {
1087
+ if (typeof entry === "string") {
1088
+ if (!headStyles || !headStyles.has(entry)) links.push(entry);
1089
+ } else if (!entry.emitted) {
1090
+ entry.emitted = true;
1091
+ inline.push(entry);
1041
1092
  }
1042
1093
  }
1043
- return result;
1094
+ return {
1095
+ links,
1096
+ inline
1097
+ };
1098
+ }
1099
+ function escapeStyleContent(content) {
1100
+ return content.replace(/<\/(style)/gi, "<\\/$1");
1101
+ }
1102
+ function renderInlineStyle(entry, nonce) {
1103
+ let attrs = "";
1104
+ if (entry.attrs) {
1105
+ for (const name in entry.attrs) {
1106
+ attrs += ` ${name}="${escape(String(entry.attrs[name]), true)}"`;
1107
+ }
1108
+ }
1109
+ return `<style${nonce ? ` nonce="${nonce}"` : ""} data-asset="${escape(entry.id, true)}"${attrs}>${escapeStyleContent(entry.content)}</style>`;
1110
+ }
1111
+ function injectInlineStyles(inlineStyles, html, nonce) {
1112
+ if (!inlineStyles.size) return html;
1113
+ const index = html.indexOf("</head>");
1114
+ if (index === -1) return html;
1115
+ let out = "";
1116
+ for (const entry of inlineStyles.values()) {
1117
+ if (entry.emitted) continue;
1118
+ entry.emitted = true;
1119
+ out += renderInlineStyle(entry, nonce);
1120
+ }
1121
+ return out ? html.slice(0, index) + out + html.slice(index) : html;
1044
1122
  }
1045
1123
  function injectScripts(html, scripts, nonce) {
1046
1124
  const tag = `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>`;
@@ -1229,4 +1307,4 @@ function Portal(props) {
1229
1307
  throw new Error("Portal is not supported on the server");
1230
1308
  }
1231
1309
 
1232
- export { Assets, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, HydrationScript, MathMLElements, Namespaces, Portal, RawTextElements, RequestContext, SVGElements, VoidElements, notSup as addEvent, applyRef, notSup as assign, notSup as className, notSup as delegateEvents, dynamic, notSup as dynamicProperty, effect, escape, generateHydrationScript, getAssets, notSup as getDelegatedRoot, getHydrationKey, notSup as getNextElement, notSup as getNextMarker, notSup as getNextMatch, getRequestEvent, notSup as hydrate, notSup as insert, isDev, isServer, memo, notSup as ref, notSup as registerDelegatedContainer, notSup as registerDelegatedRoot, notSup as render, renderToStream, renderToString, renderToStringAsync, notSup as runHydrationEvents, notSup as setAttribute, notSup as setAttributeNS, notSup as setProperty, notSup as setStyleProperty, notSup as spread, ssr, ssrAttribute, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrStyle, ssrStyleProperty, notSup as style, notSup as template, notSup as unregisterDelegatedContainer, notSup as unregisterDelegatedRoot, useAssets };
1310
+ export { Assets, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, HydrationScript, MathMLElements, Namespaces, Portal, RawTextElements, RequestContext, SVGElements, VoidElements, notSup as acquireAsset, notSup as addEvent, applyRef, notSup as assign, notSup as className, notSup as delegateEvents, dynamic, notSup as dynamicProperty, effect, escape, generateHydrationScript, getAssets, notSup as getDelegatedRoot, getHydrationKey, notSup as getNextElement, notSup as getNextMarker, notSup as getNextMatch, getRequestEvent, notSup as hydrate, notSup as insert, isDev, isServer, memo, notSup as ref, notSup as registerDelegatedContainer, notSup as registerDelegatedRoot, notSup as render, renderToStream, renderToString, renderToStringAsync, notSup as runHydrationEvents, notSup as setAttribute, notSup as setAttributeNS, notSup as setProperty, notSup as setStyleProperty, notSup as spread, ssr, ssrAttribute, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrStyle, ssrStyleProperty, notSup as style, notSup as template, notSup as unregisterDelegatedContainer, notSup as unregisterDelegatedRoot, useAssets };
package/dist/web.cjs CHANGED
@@ -504,22 +504,117 @@ function assign(node, props, skipChildren, prevProps = {}, skipRef = false) {
504
504
  prevProps[prop] = assignProp(node, prop, props[prop], prevProps[prop], skipRef, nodeName);
505
505
  }
506
506
  }
507
+ const ASSET_REMOVAL_GRACE = 100;
508
+ const assetRegistry = new Map();
509
+ function assetEntryKey(descriptor) {
510
+ if (descriptor.policy === "exclusive") return "x|" + descriptor.key;
511
+ return descriptor.type === "inline-style" ? "i|" + descriptor.id : descriptor.type + "|" + descriptor.href;
512
+ }
513
+ function findAssetElement(selector, attr, value) {
514
+ const nodes = document.querySelectorAll(selector);
515
+ for (let i = 0; i < nodes.length; i++) {
516
+ if (nodes[i].getAttribute(attr) === value) return nodes[i];
517
+ }
518
+ return null;
519
+ }
520
+ function mountAssetElement(descriptor) {
521
+ let el;
522
+ if (descriptor.type === "inline-style") {
523
+ el = findAssetElement("style[data-asset]", "data-asset", descriptor.id);
524
+ if (!el) {
525
+ el = document.createElement("style");
526
+ el.setAttribute("data-asset", descriptor.id);
527
+ el.textContent = descriptor.content || "";
528
+ }
529
+ } else {
530
+ const rel = descriptor.type === "module" ? "modulepreload" : "stylesheet";
531
+ el = findAssetElement(`link[rel="${rel}"]`, "href", descriptor.href);
532
+ if (!el) {
533
+ el = document.createElement("link");
534
+ el.rel = rel;
535
+ el.href = descriptor.href;
536
+ }
537
+ }
538
+ if (descriptor.attrs) {
539
+ for (const name in descriptor.attrs) el.setAttribute(name, descriptor.attrs[name]);
540
+ }
541
+ if (!el.isConnected) document.head.appendChild(el);
542
+ return el;
543
+ }
544
+ function acquireAsset(descriptor) {
545
+ const key = assetEntryKey(descriptor);
546
+ let entry = assetRegistry.get(key);
547
+ if (descriptor.policy === "exclusive") {
548
+ if (!entry) {
549
+ entry = {
550
+ original: descriptor.get(),
551
+ set: descriptor.set,
552
+ writers: []
553
+ };
554
+ assetRegistry.set(key, entry);
555
+ }
556
+ const writer = {
557
+ value: descriptor.value
558
+ };
559
+ entry.writers.push(writer);
560
+ entry.set(writer.value);
561
+ let released = false;
562
+ return () => {
563
+ if (released) return;
564
+ released = true;
565
+ const index = entry.writers.indexOf(writer);
566
+ const wasTop = index === entry.writers.length - 1;
567
+ entry.writers.splice(index, 1);
568
+ if (!wasTop) return;
569
+ if (entry.writers.length) {
570
+ entry.set(entry.writers[entry.writers.length - 1].value);
571
+ } else {
572
+ entry.set(entry.original);
573
+ assetRegistry.delete(key);
574
+ }
575
+ };
576
+ }
577
+ if (!entry) {
578
+ entry = {
579
+ count: 0,
580
+ element: null,
581
+ timer: null
582
+ };
583
+ assetRegistry.set(key, entry);
584
+ }
585
+ if (entry.timer) {
586
+ clearTimeout(entry.timer);
587
+ entry.timer = null;
588
+ }
589
+ entry.count++;
590
+ if (!entry.element || !entry.element.isConnected) entry.element = mountAssetElement(descriptor);
591
+ let released = false;
592
+ return () => {
593
+ if (released) return;
594
+ released = true;
595
+ if (--entry.count > 0) return;
596
+ entry.timer = setTimeout(() => {
597
+ assetRegistry.delete(key);
598
+ entry.element && entry.element.remove();
599
+ }, ASSET_REMOVAL_GRACE);
600
+ };
601
+ }
507
602
  function loadModuleAssets(mapping) {
508
603
  const hy = globalThis._$HY;
509
604
  if (!hy) return;
510
605
  const pending = [];
511
- for (const moduleUrl in mapping) {
512
- if (hy.modules[moduleUrl]) continue;
513
- const entryUrl = mapping[moduleUrl];
514
- if (!hy.loading[moduleUrl]) {
515
- hy.loading[moduleUrl] = import(entryUrl).then(mod => {
516
- hy.modules[moduleUrl] = mod;
606
+ for (const key in mapping) {
607
+ if (hy.modules[key]) continue;
608
+ const entryUrl = mapping[key];
609
+ if (!hy.loading[key]) {
610
+ hy.loading[key] = import(entryUrl).then(mod => {
611
+ hy.modules[key] = mod;
517
612
  }, err => {
518
- delete hy.loading[moduleUrl];
613
+ delete hy.loading[key];
519
614
  throw err;
520
615
  });
521
616
  }
522
- pending.push(hy.loading[moduleUrl]);
617
+ pending.push(hy.loading[key]);
523
618
  }
524
619
  return pending.length ? Promise.all(pending).then(() => {}) : undefined;
525
620
  }
@@ -806,7 +901,13 @@ function insertExpression(parent, value, current, marker) {
806
901
  const tc = typeof current;
807
902
  if (tc === "string" || tc === "number") {
808
903
  parent.firstChild.data = value;
809
- } else parent.textContent = value;
904
+ } else {
905
+ const owned = ownedChildCount(current);
906
+ if (owned === -1 || owned === parent.childNodes.length) parent.textContent = value;else {
907
+ removeOwnedChildren(parent, current);
908
+ parent.insertBefore(document.createTextNode(value), parent.firstChild);
909
+ }
910
+ }
810
911
  } else if (value === undefined) {
811
912
  cleanChildren(parent, current, marker);
812
913
  } else if (value.nodeType) {
@@ -829,7 +930,7 @@ function insertExpression(parent, value, current, marker) {
829
930
  appendNodes(parent, value, marker);
830
931
  } else reconcileArrays(parent, current, value, marker);
831
932
  } else {
832
- current && cleanChildren(parent);
933
+ current && cleanChildren(parent, current);
833
934
  appendNodes(parent, value);
834
935
  }
835
936
  } else ;
@@ -869,8 +970,31 @@ function appendNodes(parent, array, marker = null) {
869
970
  if (marker) n[$$SLOT] = marker;
870
971
  }
871
972
  }
973
+ function ownedChildCount(current) {
974
+ if (Array.isArray(current)) return current.length;
975
+ if (current == null) return -1;
976
+ if (current === "") return 0;
977
+ return 1;
978
+ }
979
+ function removeOwnedChildren(parent, current) {
980
+ if (Array.isArray(current)) {
981
+ for (let i = 0; i < current.length; i++) {
982
+ const el = current[i];
983
+ if (el.parentNode === parent) el.remove();
984
+ }
985
+ } else if (current.nodeType) {
986
+ if (current.parentNode === parent) current.remove();
987
+ } else {
988
+ const first = parent.firstChild;
989
+ if (first && first.nodeType === 3) first.remove();
990
+ }
991
+ }
872
992
  function cleanChildren(parent, current, marker, replacement) {
873
- if (marker === undefined) return parent.textContent = "";
993
+ if (marker === undefined) {
994
+ const owned = ownedChildCount(current);
995
+ if (owned === -1 || owned === parent.childNodes.length) return parent.textContent = "";
996
+ return removeOwnedChildren(parent, current);
997
+ }
874
998
  if (current.length) {
875
999
  let inserted = false;
876
1000
  for (let i = current.length - 1; i >= 0; i--) {
@@ -1072,6 +1196,7 @@ exports.RawTextElements = RawTextElements;
1072
1196
  exports.RequestContext = RequestContext;
1073
1197
  exports.SVGElements = SVGElements;
1074
1198
  exports.VoidElements = VoidElements;
1199
+ exports.acquireAsset = acquireAsset;
1075
1200
  exports.addEvent = addEvent;
1076
1201
  exports.applyRef = applyRef;
1077
1202
  exports.assign = assign;
package/dist/web.js CHANGED
@@ -503,22 +503,117 @@ function assign(node, props, skipChildren, prevProps = {}, skipRef = false) {
503
503
  prevProps[prop] = assignProp(node, prop, props[prop], prevProps[prop], skipRef, nodeName);
504
504
  }
505
505
  }
506
+ const ASSET_REMOVAL_GRACE = 100;
507
+ const assetRegistry = new Map();
508
+ function assetEntryKey(descriptor) {
509
+ if (descriptor.policy === "exclusive") return "x|" + descriptor.key;
510
+ return descriptor.type === "inline-style" ? "i|" + descriptor.id : descriptor.type + "|" + descriptor.href;
511
+ }
512
+ function findAssetElement(selector, attr, value) {
513
+ const nodes = document.querySelectorAll(selector);
514
+ for (let i = 0; i < nodes.length; i++) {
515
+ if (nodes[i].getAttribute(attr) === value) return nodes[i];
516
+ }
517
+ return null;
518
+ }
519
+ function mountAssetElement(descriptor) {
520
+ let el;
521
+ if (descriptor.type === "inline-style") {
522
+ el = findAssetElement("style[data-asset]", "data-asset", descriptor.id);
523
+ if (!el) {
524
+ el = document.createElement("style");
525
+ el.setAttribute("data-asset", descriptor.id);
526
+ el.textContent = descriptor.content || "";
527
+ }
528
+ } else {
529
+ const rel = descriptor.type === "module" ? "modulepreload" : "stylesheet";
530
+ el = findAssetElement(`link[rel="${rel}"]`, "href", descriptor.href);
531
+ if (!el) {
532
+ el = document.createElement("link");
533
+ el.rel = rel;
534
+ el.href = descriptor.href;
535
+ }
536
+ }
537
+ if (descriptor.attrs) {
538
+ for (const name in descriptor.attrs) el.setAttribute(name, descriptor.attrs[name]);
539
+ }
540
+ if (!el.isConnected) document.head.appendChild(el);
541
+ return el;
542
+ }
543
+ function acquireAsset(descriptor) {
544
+ const key = assetEntryKey(descriptor);
545
+ let entry = assetRegistry.get(key);
546
+ if (descriptor.policy === "exclusive") {
547
+ if (!entry) {
548
+ entry = {
549
+ original: descriptor.get(),
550
+ set: descriptor.set,
551
+ writers: []
552
+ };
553
+ assetRegistry.set(key, entry);
554
+ }
555
+ const writer = {
556
+ value: descriptor.value
557
+ };
558
+ entry.writers.push(writer);
559
+ entry.set(writer.value);
560
+ let released = false;
561
+ return () => {
562
+ if (released) return;
563
+ released = true;
564
+ const index = entry.writers.indexOf(writer);
565
+ const wasTop = index === entry.writers.length - 1;
566
+ entry.writers.splice(index, 1);
567
+ if (!wasTop) return;
568
+ if (entry.writers.length) {
569
+ entry.set(entry.writers[entry.writers.length - 1].value);
570
+ } else {
571
+ entry.set(entry.original);
572
+ assetRegistry.delete(key);
573
+ }
574
+ };
575
+ }
576
+ if (!entry) {
577
+ entry = {
578
+ count: 0,
579
+ element: null,
580
+ timer: null
581
+ };
582
+ assetRegistry.set(key, entry);
583
+ }
584
+ if (entry.timer) {
585
+ clearTimeout(entry.timer);
586
+ entry.timer = null;
587
+ }
588
+ entry.count++;
589
+ if (!entry.element || !entry.element.isConnected) entry.element = mountAssetElement(descriptor);
590
+ let released = false;
591
+ return () => {
592
+ if (released) return;
593
+ released = true;
594
+ if (--entry.count > 0) return;
595
+ entry.timer = setTimeout(() => {
596
+ assetRegistry.delete(key);
597
+ entry.element && entry.element.remove();
598
+ }, ASSET_REMOVAL_GRACE);
599
+ };
600
+ }
506
601
  function loadModuleAssets(mapping) {
507
602
  const hy = globalThis._$HY;
508
603
  if (!hy) return;
509
604
  const pending = [];
510
- for (const moduleUrl in mapping) {
511
- if (hy.modules[moduleUrl]) continue;
512
- const entryUrl = mapping[moduleUrl];
513
- if (!hy.loading[moduleUrl]) {
514
- hy.loading[moduleUrl] = import(entryUrl).then(mod => {
515
- hy.modules[moduleUrl] = mod;
605
+ for (const key in mapping) {
606
+ if (hy.modules[key]) continue;
607
+ const entryUrl = mapping[key];
608
+ if (!hy.loading[key]) {
609
+ hy.loading[key] = import(entryUrl).then(mod => {
610
+ hy.modules[key] = mod;
516
611
  }, err => {
517
- delete hy.loading[moduleUrl];
612
+ delete hy.loading[key];
518
613
  throw err;
519
614
  });
520
615
  }
521
- pending.push(hy.loading[moduleUrl]);
616
+ pending.push(hy.loading[key]);
522
617
  }
523
618
  return pending.length ? Promise.all(pending).then(() => {}) : undefined;
524
619
  }
@@ -805,7 +900,13 @@ function insertExpression(parent, value, current, marker) {
805
900
  const tc = typeof current;
806
901
  if (tc === "string" || tc === "number") {
807
902
  parent.firstChild.data = value;
808
- } else parent.textContent = value;
903
+ } else {
904
+ const owned = ownedChildCount(current);
905
+ if (owned === -1 || owned === parent.childNodes.length) parent.textContent = value;else {
906
+ removeOwnedChildren(parent, current);
907
+ parent.insertBefore(document.createTextNode(value), parent.firstChild);
908
+ }
909
+ }
809
910
  } else if (value === undefined) {
810
911
  cleanChildren(parent, current, marker);
811
912
  } else if (value.nodeType) {
@@ -828,7 +929,7 @@ function insertExpression(parent, value, current, marker) {
828
929
  appendNodes(parent, value, marker);
829
930
  } else reconcileArrays(parent, current, value, marker);
830
931
  } else {
831
- current && cleanChildren(parent);
932
+ current && cleanChildren(parent, current);
832
933
  appendNodes(parent, value);
833
934
  }
834
935
  } else ;
@@ -868,8 +969,31 @@ function appendNodes(parent, array, marker = null) {
868
969
  if (marker) n[$$SLOT] = marker;
869
970
  }
870
971
  }
972
+ function ownedChildCount(current) {
973
+ if (Array.isArray(current)) return current.length;
974
+ if (current == null) return -1;
975
+ if (current === "") return 0;
976
+ return 1;
977
+ }
978
+ function removeOwnedChildren(parent, current) {
979
+ if (Array.isArray(current)) {
980
+ for (let i = 0; i < current.length; i++) {
981
+ const el = current[i];
982
+ if (el.parentNode === parent) el.remove();
983
+ }
984
+ } else if (current.nodeType) {
985
+ if (current.parentNode === parent) current.remove();
986
+ } else {
987
+ const first = parent.firstChild;
988
+ if (first && first.nodeType === 3) first.remove();
989
+ }
990
+ }
871
991
  function cleanChildren(parent, current, marker, replacement) {
872
- if (marker === undefined) return parent.textContent = "";
992
+ if (marker === undefined) {
993
+ const owned = ownedChildCount(current);
994
+ if (owned === -1 || owned === parent.childNodes.length) return parent.textContent = "";
995
+ return removeOwnedChildren(parent, current);
996
+ }
873
997
  if (current.length) {
874
998
  let inserted = false;
875
999
  for (let i = current.length - 1; i >= 0; i--) {
@@ -1005,4 +1129,4 @@ function createElement(tagName, is = undefined) {
1005
1129
  });
1006
1130
  }
1007
1131
 
1008
- export { voidFn as Assets, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, voidFn as HydrationScript, MathMLElements, Namespaces, Portal, RawTextElements, RequestContext, SVGElements, VoidElements, addEvent, applyRef, assign, className, delegateEvents, dynamic, dynamicProperty, effect, escape, voidFn as generateHydrationScript, voidFn as getAssets, getDelegatedRoot, getFirstChild, getHydrationKey, getNextElement, getNextMarker, getNextMatch, getNextSibling, voidFn as getRequestEvent, hydrate, insert, isDev, isServer, memo, mergeProps, ref, registerDelegatedContainer, registerDelegatedRoot, render, renderToStream, renderToString, renderToStringAsync, resolveSSRNode, runHydrationEvents, scope, setAttribute, setAttributeNS, setProperty, setStyleProperty, spread, ssr, ssrAttribute, ssrClassList, ssrElement, ssrHydrationKey, ssrStyle, style, template, unregisterDelegatedContainer, unregisterDelegatedRoot, voidFn as useAssets };
1132
+ export { voidFn as Assets, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, voidFn as HydrationScript, MathMLElements, Namespaces, Portal, RawTextElements, RequestContext, SVGElements, VoidElements, acquireAsset, addEvent, applyRef, assign, className, delegateEvents, dynamic, dynamicProperty, effect, escape, voidFn as generateHydrationScript, voidFn as getAssets, getDelegatedRoot, getFirstChild, getHydrationKey, getNextElement, getNextMarker, getNextMatch, getNextSibling, voidFn as getRequestEvent, hydrate, insert, isDev, isServer, memo, mergeProps, ref, registerDelegatedContainer, registerDelegatedRoot, render, renderToStream, renderToString, renderToStringAsync, resolveSSRNode, runHydrationEvents, scope, setAttribute, setAttributeNS, setProperty, setStyleProperty, spread, ssr, ssrAttribute, ssrClassList, ssrElement, ssrHydrationKey, ssrStyle, style, template, unregisterDelegatedContainer, unregisterDelegatedRoot, voidFn as useAssets };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@solidjs/web",
3
3
  "description": "Solid's web runtime: client rendering, hydration, SSR, and DOM-specific control flow (Portal, Dynamic).",
4
- "version": "2.0.0-beta.16",
4
+ "version": "2.0.0-beta.17",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
7
7
  "homepage": "https://solidjs.com",
@@ -137,10 +137,10 @@
137
137
  "seroval-plugins": "^1.1.0"
138
138
  },
139
139
  "peerDependencies": {
140
- "solid-js": "^2.0.0-beta.16"
140
+ "solid-js": "^2.0.0-beta.17"
141
141
  },
142
142
  "devDependencies": {
143
- "solid-js": "2.0.0-beta.16"
143
+ "solid-js": "2.0.0-beta.17"
144
144
  },
145
145
  "scripts": {
146
146
  "build": "npm-run-all -nl build:clean types:copy-jsx build:js",
package/types/client.d.ts CHANGED
@@ -103,6 +103,19 @@ export function getNextMatch(start: Node, elementName: string): Element;
103
103
  export function getNextMarker(start: Node): [Node, Array<Node>];
104
104
  export function useAssets(fn: () => JSX.Element): void;
105
105
  export function getAssets(): string;
106
+ export type AssetDescriptor =
107
+ | { type: "style"; href: string; attrs?: Record<string, string> }
108
+ | { type: "inline-style"; id: string; content?: string; attrs?: Record<string, string> }
109
+ | { type: "module"; href: string }
110
+ | ExclusiveAssetDescriptor<any>;
111
+ export interface ExclusiveAssetDescriptor<T> {
112
+ policy: "exclusive";
113
+ key: string;
114
+ value: T;
115
+ get(): T;
116
+ set(value: T): void;
117
+ }
118
+ export function acquireAsset(descriptor: AssetDescriptor): () => void;
106
119
  export function HydrationScript(props?: { nonce?: string; eventNames?: string[] }): JSX.Element;
107
120
  export function generateHydrationScript(options?: {
108
121
  nonce?: string;
package/types/server.d.ts CHANGED
@@ -192,3 +192,5 @@ export function ref(
192
192
  ): void;
193
193
  /** @deprecated not supported on the server side */
194
194
  export function setStyleProperty(node: Element, name: string, value: any): void;
195
+ /** @deprecated not supported on the server side — register assets through the render context instead */
196
+ export function acquireAsset(descriptor: unknown): () => void;
@@ -103,6 +103,19 @@ export function getNextMatch(start: Node, elementName: string): Element;
103
103
  export function getNextMarker(start: Node): [Node, Array<Node>];
104
104
  export function useAssets(fn: () => JSX.Element): void;
105
105
  export function getAssets(): string;
106
+ export type AssetDescriptor =
107
+ | { type: "style"; href: string; attrs?: Record<string, string> }
108
+ | { type: "inline-style"; id: string; content?: string; attrs?: Record<string, string> }
109
+ | { type: "module"; href: string }
110
+ | ExclusiveAssetDescriptor<any>;
111
+ export interface ExclusiveAssetDescriptor<T> {
112
+ policy: "exclusive";
113
+ key: string;
114
+ value: T;
115
+ get(): T;
116
+ set(value: T): void;
117
+ }
118
+ export function acquireAsset(descriptor: AssetDescriptor): () => void;
106
119
  export function HydrationScript(props?: { nonce?: string; eventNames?: string[] }): JSX.Element;
107
120
  export function generateHydrationScript(options?: {
108
121
  nonce?: string;
@@ -192,3 +192,5 @@ export function ref(
192
192
  ): void;
193
193
  /** @deprecated not supported on the server side */
194
194
  export function setStyleProperty(node: Element, name: string, value: any): void;
195
+ /** @deprecated not supported on the server side — register assets through the render context instead */
196
+ export function acquireAsset(descriptor: unknown): () => void;