@solidjs/web 2.0.0-beta.29 → 2.0.0-beta.30
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 +329 -2
- package/dist/dev.js +329 -3
- package/dist/server.cjs +451 -20
- package/dist/server.js +451 -21
- package/dist/web.cjs +325 -2
- package/dist/web.js +325 -3
- package/frames/dist/client.cjs +177 -34
- package/frames/dist/client.dev.cjs +177 -34
- package/frames/dist/client.dev.js +178 -35
- package/frames/dist/client.js +178 -35
- package/frames/dist/server.cjs +405 -17
- package/frames/dist/server.js +405 -17
- package/package.json +3 -3
- package/types/client.d.ts +20 -0
- package/types/frames/frame-client.d.ts +25 -0
- package/types/frames/frame-transport.d.ts +26 -0
- package/types/index.d.ts +1 -22
- package/types/server.d.ts +50 -0
- package/types-cjs/client.d.cts +20 -0
- package/types-cjs/frames/frame-client.d.cts +25 -0
- package/types-cjs/frames/frame-transport.d.cts +26 -0
- package/types-cjs/index.d.cts +1 -22
- package/types-cjs/server.d.cts +50 -0
package/frames/dist/server.cjs
CHANGED
|
@@ -137,6 +137,90 @@ function createJSONSerializer({
|
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
const HEAD_ELIGIBLE_TAGS = new Set(["title", "meta", "link", "style", "script", "base"]);
|
|
141
|
+
const HEAD_ATTR_NAME = /^[a-zA-Z_][a-zA-Z0-9_:.-]*$/;
|
|
142
|
+
const RESOURCE_LINK_RELS = new Set(["preload", "modulepreload", "prefetch", "preconnect", "dns-prefetch", "icon", "stylesheet"]);
|
|
143
|
+
const RESOURCE_QUALIFIERS = ["as", "crossorigin", "type", "media", "imagesrcset", "imagesizes"];
|
|
144
|
+
const STYLESHEET_FETCH_META = new Set(["crossorigin", "integrity", "referrerpolicy", "fetchpriority"]);
|
|
145
|
+
function evalHeadValue(v) {
|
|
146
|
+
return typeof v === "function" ? v() : v;
|
|
147
|
+
}
|
|
148
|
+
function evalHeadProps(props, presets) {
|
|
149
|
+
const out = {};
|
|
150
|
+
for (const name in props) out[name] = presets && name in presets ? presets[name] : evalHeadValue(props[name]);
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
function classifyHeadTag(desc) {
|
|
154
|
+
const tag = desc.tag;
|
|
155
|
+
if (tag === "link") {
|
|
156
|
+
const rel = evalHeadValue(desc.props && desc.props.rel);
|
|
157
|
+
return {
|
|
158
|
+
resource: RESOURCE_LINK_RELS.has(rel),
|
|
159
|
+
rel
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (tag === "style") return {
|
|
163
|
+
resource: !!(desc.props && "href" in desc.props)
|
|
164
|
+
};
|
|
165
|
+
if (tag === "script") return {
|
|
166
|
+
resource: !!(desc.props && "src" in desc.props)
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
resource: false
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function resourceIdentity(tag, props) {
|
|
173
|
+
let id = "res:" + tag + ":" + (props.rel || "") + ":" + (props.href || props.src || "");
|
|
174
|
+
for (let i = 0; i < RESOURCE_QUALIFIERS.length; i++) {
|
|
175
|
+
const q = RESOURCE_QUALIFIERS[i];
|
|
176
|
+
if (props[q] != null) id += ":" + q + "=" + props[q];
|
|
177
|
+
}
|
|
178
|
+
return id;
|
|
179
|
+
}
|
|
180
|
+
function replaceableIdentity(tag, props, key, unique) {
|
|
181
|
+
if (tag === "title") return "title";
|
|
182
|
+
if (tag === "base") return "base";
|
|
183
|
+
if (tag === "meta" && props.charset != null) return "charset";
|
|
184
|
+
if (key != null) return tag + ":key:" + key;
|
|
185
|
+
if (tag === "meta") {
|
|
186
|
+
if (props.name != null) return "meta:name:" + props.name;
|
|
187
|
+
if (props.property != null) return "meta:property:" + props.property;
|
|
188
|
+
if (props["http-equiv"] != null) return "meta:http-equiv:" + props["http-equiv"];
|
|
189
|
+
return unique;
|
|
190
|
+
}
|
|
191
|
+
if (tag === "link") return "link:" + (props.rel || "") + ":" + (props.href || "");
|
|
192
|
+
return unique;
|
|
193
|
+
}
|
|
194
|
+
function resolveHead(groups) {
|
|
195
|
+
const winners = new Map();
|
|
196
|
+
const sorted = groups.slice().sort((a, b) => a.seq - b.seq);
|
|
197
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
198
|
+
const group = sorted[i];
|
|
199
|
+
const byIdentity = new Map();
|
|
200
|
+
for (let j = 0; j < group.tags.length; j++) {
|
|
201
|
+
const t = group.tags[j];
|
|
202
|
+
let list = byIdentity.get(t.identity);
|
|
203
|
+
if (!list) byIdentity.set(t.identity, list = []);
|
|
204
|
+
list.push(t);
|
|
205
|
+
}
|
|
206
|
+
for (const [identity, tags] of byIdentity) {
|
|
207
|
+
if (identity === "title") {
|
|
208
|
+
if (tags.length > 1) console.warn("Multiple <title> tags in one head group; the last one wins.");
|
|
209
|
+
winners.set(identity, {
|
|
210
|
+
seq: group.seq,
|
|
211
|
+
tags: [tags[tags.length - 1]]
|
|
212
|
+
});
|
|
213
|
+
} else {
|
|
214
|
+
winners.set(identity, {
|
|
215
|
+
seq: group.seq,
|
|
216
|
+
tags
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return winners;
|
|
222
|
+
}
|
|
223
|
+
|
|
140
224
|
function joinAssetPath(base, file) {
|
|
141
225
|
if (/^(?:[a-z][a-z0-9+.-]*:)?\/\//i.test(file)) return file;
|
|
142
226
|
if (typeof base !== "string" || !base) base = "/";
|
|
@@ -278,7 +362,258 @@ function applyAssetTracking(context, tracking, manifest, noScripts) {
|
|
|
278
362
|
context.resolveAssetsSync = resolve;
|
|
279
363
|
}
|
|
280
364
|
}
|
|
281
|
-
|
|
365
|
+
function isCssUrl(url) {
|
|
366
|
+
const q = url.search(/[?#]/);
|
|
367
|
+
return (q === -1 ? url : url.slice(0, q)).endsWith(".css");
|
|
368
|
+
}
|
|
369
|
+
function createHeadRegistry() {
|
|
370
|
+
return {
|
|
371
|
+
pending: [],
|
|
372
|
+
committed: [],
|
|
373
|
+
seq: 0,
|
|
374
|
+
uniq: 0,
|
|
375
|
+
resources: new Set(),
|
|
376
|
+
eagerHtml: "",
|
|
377
|
+
flushed: null,
|
|
378
|
+
shellFlushed: false
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function registerHeadTags(registry, context, tracking, emitResource, nonce, tags) {
|
|
382
|
+
const boundary = context._currentBoundaryId || "";
|
|
383
|
+
let replaceable = null;
|
|
384
|
+
for (let i = 0; i < tags.length; i++) {
|
|
385
|
+
const desc = tags[i];
|
|
386
|
+
if (!desc || !HEAD_ELIGIBLE_TAGS.has(desc.tag)) {
|
|
387
|
+
console.warn(`useHead: ignoring non-head tag`, desc);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const cls = classifyHeadTag(desc);
|
|
391
|
+
if (cls.resource) {
|
|
392
|
+
emitHeadResource(registry, context, tracking, emitResource, nonce, desc, cls.rel);
|
|
393
|
+
} else {
|
|
394
|
+
(replaceable || (replaceable = [])).push(cls.rel !== undefined ? {
|
|
395
|
+
tag: desc.tag,
|
|
396
|
+
props: desc.props,
|
|
397
|
+
key: desc.key,
|
|
398
|
+
rel: cls.rel
|
|
399
|
+
} : desc);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (replaceable) registry.pending.push({
|
|
403
|
+
boundary,
|
|
404
|
+
tags: replaceable
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
function emitHeadResource(registry, context, tracking, emitResource, nonce, desc, rel) {
|
|
408
|
+
let props;
|
|
409
|
+
try {
|
|
410
|
+
props = evalHeadProps(desc.props || {}, rel !== undefined ? {
|
|
411
|
+
rel
|
|
412
|
+
} : undefined);
|
|
413
|
+
} catch (err) {
|
|
414
|
+
console.warn(`useHead: error evaluating resource tag props`, err);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const identity = resourceIdentity(desc.tag, props);
|
|
418
|
+
if (registry.resources.has(identity)) return;
|
|
419
|
+
registry.resources.add(identity);
|
|
420
|
+
if (desc.tag === "link" && (rel === "stylesheet" || rel === "modulepreload")) {
|
|
421
|
+
let plain = true;
|
|
422
|
+
let gateable = rel === "stylesheet";
|
|
423
|
+
for (const name in props) {
|
|
424
|
+
if (name === "rel" || name === "href") continue;
|
|
425
|
+
plain = false;
|
|
426
|
+
if (!STYLESHEET_FETCH_META.has(name)) gateable = false;
|
|
427
|
+
}
|
|
428
|
+
if (plain && props.href != null) {
|
|
429
|
+
const isCss = isCssUrl(props.href);
|
|
430
|
+
if (rel === "stylesheet" ? isCss : !isCss) {
|
|
431
|
+
context.registerAsset(rel === "stylesheet" ? "style" : "module", props.href);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (gateable && props.href != null) {
|
|
436
|
+
const attrHtml = renderHeadAttrHtml(props);
|
|
437
|
+
const entry = {
|
|
438
|
+
href: props.href,
|
|
439
|
+
attrHtml,
|
|
440
|
+
attrs: headAttrRecord(props)
|
|
441
|
+
};
|
|
442
|
+
if (tracking.currentBoundaryId) {
|
|
443
|
+
let styles = tracking.boundaryStyles.get(tracking.currentBoundaryId);
|
|
444
|
+
if (!styles) tracking.boundaryStyles.set(tracking.currentBoundaryId, styles = new Set());
|
|
445
|
+
styles.add(entry);
|
|
446
|
+
}
|
|
447
|
+
const markup = `<link${attrHtml}>`;
|
|
448
|
+
if (emitResource) emitResource(markup, entry);else {
|
|
449
|
+
registry.eagerHtml += markup;
|
|
450
|
+
entry.emitted = true;
|
|
451
|
+
}
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
const url = props.href || props.src;
|
|
456
|
+
if (url != null && tracking.emittedAssets.has(url)) return;
|
|
457
|
+
const markup = renderHeadTagMarkup(desc.tag, props, null, nonce);
|
|
458
|
+
if (emitResource) emitResource(markup);else registry.eagerHtml += markup;
|
|
459
|
+
}
|
|
460
|
+
function commitHeadBoundary(registry, boundary, isPendingFragment) {
|
|
461
|
+
const keep = [];
|
|
462
|
+
const groups = [];
|
|
463
|
+
for (let i = 0; i < registry.pending.length; i++) {
|
|
464
|
+
const reg = registry.pending[i];
|
|
465
|
+
const mine = boundary === "" ? !(isPendingFragment && reg.boundary !== "" && isPendingFragment(reg.boundary)) : reg.boundary === boundary;
|
|
466
|
+
if (!mine) {
|
|
467
|
+
keep.push(reg);
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
const tags = [];
|
|
471
|
+
for (let j = 0; j < reg.tags.length; j++) {
|
|
472
|
+
const desc = reg.tags[j];
|
|
473
|
+
let props, key;
|
|
474
|
+
try {
|
|
475
|
+
props = evalHeadProps(desc.props || {}, desc.rel !== undefined ? {
|
|
476
|
+
rel: desc.rel
|
|
477
|
+
} : undefined);
|
|
478
|
+
key = evalHeadValue(desc.key);
|
|
479
|
+
} catch (err) {
|
|
480
|
+
console.warn(`useHead: error evaluating tag props`, err);
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
const identity = replaceableIdentity(desc.tag, props, key, "u:" + registry.uniq++);
|
|
484
|
+
if ((identity === "base" || identity === "charset") && registry.shellFlushed) {
|
|
485
|
+
console.warn(`useHead: <${desc.tag}> (${identity}) registered after shell flush is ignored`);
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
tags.push({
|
|
489
|
+
tag: desc.tag,
|
|
490
|
+
props,
|
|
491
|
+
identity
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
if (tags.length) groups.push({
|
|
495
|
+
seq: registry.seq++,
|
|
496
|
+
tags
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
registry.pending = keep;
|
|
500
|
+
for (let i = 0; i < groups.length; i++) registry.committed.push(groups[i]);
|
|
501
|
+
return groups;
|
|
502
|
+
}
|
|
503
|
+
function adoptHeadBoundary(registry, childKey, parentKey) {
|
|
504
|
+
for (let i = 0; i < registry.pending.length; i++) {
|
|
505
|
+
if (registry.pending[i].boundary === childKey) registry.pending[i].boundary = parentKey;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
function dropHeadBoundary(registry, boundary) {
|
|
509
|
+
registry.pending = registry.pending.filter(reg => reg.boundary !== boundary);
|
|
510
|
+
}
|
|
511
|
+
function headGroupSignature(winner) {
|
|
512
|
+
let sig = "" + winner.seq;
|
|
513
|
+
for (let i = 0; i < winner.tags.length; i++) {
|
|
514
|
+
const t = winner.tags[i];
|
|
515
|
+
sig += "|" + t.tag + JSON.stringify(t.props);
|
|
516
|
+
}
|
|
517
|
+
return sig;
|
|
518
|
+
}
|
|
519
|
+
function renderShellHead(registry, nonce, isPendingFragment) {
|
|
520
|
+
commitHeadBoundary(registry, "", isPendingFragment);
|
|
521
|
+
registry.shellFlushed = true;
|
|
522
|
+
const winners = resolveHead(registry.committed);
|
|
523
|
+
registry.flushed = new Map();
|
|
524
|
+
let prelude = "";
|
|
525
|
+
let links = "";
|
|
526
|
+
let metas = "";
|
|
527
|
+
let others = "";
|
|
528
|
+
let scripts = "";
|
|
529
|
+
for (const [identity, winner] of winners) {
|
|
530
|
+
registry.flushed.set(identity, headGroupSignature(winner));
|
|
531
|
+
for (let i = 0; i < winner.tags.length; i++) {
|
|
532
|
+
const t = winner.tags[i];
|
|
533
|
+
const markup = renderHeadTagMarkup(t.tag, t.props, identity, nonce);
|
|
534
|
+
if (identity === "charset" || identity === "base") prelude += markup;else if (t.tag === "link" || t.tag === "style") links += markup;else if (t.tag === "meta") metas += markup;else if (t.tag === "script") scripts += markup;else others += markup;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return {
|
|
538
|
+
prelude,
|
|
539
|
+
html: registry.eagerHtml + links + metas + others + scripts
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function flushHeadFragment(registry, boundary) {
|
|
543
|
+
const groups = commitHeadBoundary(registry, boundary);
|
|
544
|
+
if (!groups.length) return null;
|
|
545
|
+
const winners = resolveHead(registry.committed);
|
|
546
|
+
const affected = new Set();
|
|
547
|
+
for (let i = 0; i < groups.length; i++) for (let j = 0; j < groups[i].tags.length; j++) affected.add(groups[i].tags[j].identity);
|
|
548
|
+
const ops = [];
|
|
549
|
+
for (const identity of affected) {
|
|
550
|
+
const winner = winners.get(identity);
|
|
551
|
+
const sig = headGroupSignature(winner);
|
|
552
|
+
if (registry.flushed.get(identity) === sig) continue;
|
|
553
|
+
const existed = registry.flushed.has(identity);
|
|
554
|
+
registry.flushed.set(identity, sig);
|
|
555
|
+
if (identity === "title") {
|
|
556
|
+
const children = winner.tags[0].props.children;
|
|
557
|
+
ops.push(["t", children == null ? "" : String(children)]);
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
if (existed) ops.push(["r", identity]);
|
|
561
|
+
for (let i = 0; i < winner.tags.length; i++) {
|
|
562
|
+
const t = winner.tags[i];
|
|
563
|
+
const attrs = {};
|
|
564
|
+
for (const name in t.props) {
|
|
565
|
+
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
|
|
566
|
+
if (!HEAD_ATTR_NAME.test(name)) {
|
|
567
|
+
console.warn(`useHead: ignoring invalid attribute name "${name}"`);
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
const v = t.props[name];
|
|
571
|
+
if (v == null || v === false) continue;
|
|
572
|
+
attrs[name] = v === true ? "" : String(v);
|
|
573
|
+
}
|
|
574
|
+
const children = t.props.children;
|
|
575
|
+
ops.push(["a", identity, t.tag, attrs, children == null ? null : String(children)]);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return ops.length ? ops : null;
|
|
579
|
+
}
|
|
580
|
+
function renderHeadAttrHtml(props) {
|
|
581
|
+
let attrs = "";
|
|
582
|
+
for (const name in props) {
|
|
583
|
+
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
|
|
584
|
+
if (!HEAD_ATTR_NAME.test(name)) {
|
|
585
|
+
console.warn(`useHead: ignoring invalid attribute name "${name}"`);
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
const v = props[name];
|
|
589
|
+
if (v == null || v === false) continue;
|
|
590
|
+
attrs += v === true ? ` ${name}` : ` ${name}="${escape(String(v), true)}"`;
|
|
591
|
+
}
|
|
592
|
+
return attrs;
|
|
593
|
+
}
|
|
594
|
+
function headAttrRecord(props, skipRelHref) {
|
|
595
|
+
let attrs = null;
|
|
596
|
+
for (const name in props) {
|
|
597
|
+
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
|
|
598
|
+
if ((name === "rel" || name === "href")) continue;
|
|
599
|
+
if (!HEAD_ATTR_NAME.test(name)) continue;
|
|
600
|
+
const v = props[name];
|
|
601
|
+
if (v == null || v === false) continue;
|
|
602
|
+
(attrs || (attrs = {}))[name] = v === true ? "" : String(v);
|
|
603
|
+
}
|
|
604
|
+
return attrs;
|
|
605
|
+
}
|
|
606
|
+
function renderHeadTagMarkup(tag, props, identity, nonce) {
|
|
607
|
+
let attrs = renderHeadAttrHtml(props);
|
|
608
|
+
if (identity != null) attrs += ` data-dh="${escape(identity, true)}"`;
|
|
609
|
+
if (nonce && (tag === "script" || tag === "style")) attrs += ` nonce="${nonce}"`;
|
|
610
|
+
if (tag === "meta" || tag === "link" || tag === "base") return `<${tag}${attrs}>`;
|
|
611
|
+
let body = props.children == null ? "" : String(props.children);
|
|
612
|
+
if (tag === "script") body = body.replace(/<\/(script)/gi, "<\\/$1");else if (tag === "style") body = escapeStyleContent(body);else body = escape(body);
|
|
613
|
+
return `<${tag}${attrs}>${body}</${tag}>`;
|
|
614
|
+
}
|
|
615
|
+
const REPLACE_SCRIPT = `function $df(e){return _$HY.f?_$HY.f(e):$dfr(e)}function $dfr(e,n,o,t){if(!(n=document.getElementById(e)))return 0;if(!(o=document.getElementById("pl-"+e)))return(_$HY.dq=_$HY.dq||{})[e]=1,0;for(;o&&(8!==o.nodeType||o.nodeValue!=="pl-"+e);)t=o.nextSibling,o.remove(),o=t;t=o.parentNode,o.replaceWith(n.content),n.remove(),_$HY.fe(e,t),_$HY.hp&&_$HY.hp[e]&&($dh(_$HY.hp[e]),delete _$HY.hp[e]),$dfd();return 1}function $dfl(e,o,n){if(!(o=document.getElementById("pl-"+e)))return(_$HY.dlq=_$HY.dlq||{})[e]=1,0;if(o._$fl)return 1;for(n=o.nextSibling;n;){if(8===n.nodeType&&n.nodeValue==="pl-"+e){o.parentNode&&o.parentNode.insertBefore(o.content.cloneNode(!0),n),o._$fl=1,$dfd();return 1}n=n.nextSibling}return 0}function $dflj(e,i){for(i=0;i<e.length;i++)$dfl(e[i])}function $dfd(e,i){if(e=_$HY.dq){_$HY.dq=0;for(i in e)$df(i)}if(e=_$HY.dlq){_$HY.dlq=0;for(i in e)$dfl(i)}}function $dfs(e,c,d){(_$HY.sc=_$HY.sc||{})[e]=c,d&&((_$HY.sd=_$HY.sd||{})[e]=1)}function $dfg(e,g,i,k){if(!(g=_$HY.sg&&_$HY.sg[e]))return;for(i=0;i<g.length;i++)if(_$HY.sc&&_$HY.sc[g[i]]>0)return;for(i=0;i<g.length;i++)k=g[i],delete _$HY.sg[k],$df(k)}function $dfc(e){if(--_$HY.sc[e]<=0){delete _$HY.sc[e],_$HY.sg&&_$HY.sg[e]?$dfg(e):!(_$HY.sd&&_$HY.sd[e])&&$df(e);_$HY.sd&&delete _$HY.sd[e]}}function $dfj(e,i,n){for(i=0;i<e.length;i++)if(_$HY.sc&&_$HY.sc[e[i]]>0){for(n=0;n<e.length;n++)(_$HY.sg=_$HY.sg||{})[e[n]]=e;return}for(i=0;i<e.length;i++)$df(e[i])}`;
|
|
616
|
+
const HEAD_SCRIPT = `function $dha(o,i,e,n){for(i=0;i<o.length;i++)e=o[i],"t"==e[0]?((n=document.querySelector("title"))||(n=document.createElement("title"),document.head.appendChild(n)),n.textContent=e[1],n.setAttribute("data-dh","title")):"r"==e[0]?$dhr(e[1]):(n=document.createElement(e[2]),Object.keys(e[3]).forEach(function(a){n.setAttribute(a,e[3][a])}),null!=e[4]&&(n.textContent=e[4]),n.setAttribute("data-dh",e[1]),document.head.appendChild(n))}function $dhr(v,l,i){for(l=document.head.querySelectorAll("[data-dh]"),i=0;i<l.length;i++)l[i].getAttribute("data-dh")==v&&l[i].remove()}function $dh(o){_$HY.h?_$HY.h(o):$dha(o)}`;
|
|
282
617
|
function renderToStream(code, options = {}) {
|
|
283
618
|
let {
|
|
284
619
|
nonce,
|
|
@@ -286,7 +621,8 @@ function renderToStream(code, options = {}) {
|
|
|
286
621
|
onCompleteAll,
|
|
287
622
|
renderId = "",
|
|
288
623
|
noScripts,
|
|
289
|
-
manifest
|
|
624
|
+
manifest,
|
|
625
|
+
onHead
|
|
290
626
|
} = options;
|
|
291
627
|
let dispose;
|
|
292
628
|
const blockingPromises = new Set();
|
|
@@ -328,8 +664,8 @@ function renderToStream(code, options = {}) {
|
|
|
328
664
|
if (styles.links.length) {
|
|
329
665
|
emitTask(`$dfs("${key}",${styles.links.length},${deferActivation ? 1 : 0})`);
|
|
330
666
|
writeTasks();
|
|
331
|
-
for (const
|
|
332
|
-
buffer.write(`<link rel="stylesheet" href="${
|
|
667
|
+
for (const entry of styles.links) {
|
|
668
|
+
buffer.write(typeof entry === "string" ? `<link rel="stylesheet" href="${entry}" onload="$dfc('${key}')" onerror="$dfc('${key}')">` : `<link${entry.attrHtml} onload="$dfc('${key}')" onerror="$dfc('${key}')">`);
|
|
333
669
|
}
|
|
334
670
|
buffer.write(`<template id="${key}">${value}</template>`);
|
|
335
671
|
} else {
|
|
@@ -347,10 +683,12 @@ function renderToStream(code, options = {}) {
|
|
|
347
683
|
buffer.write(`<link rel="modulepreload" href="${value}">`);
|
|
348
684
|
} else if (type === "inline-style") {
|
|
349
685
|
buffer.write(renderInlineStyle(value, nonce));
|
|
686
|
+
} else if (type === "head-tag") {
|
|
687
|
+
buffer.write(value);
|
|
350
688
|
}
|
|
351
689
|
},
|
|
352
690
|
shell(shellHtml, meta) {
|
|
353
|
-
buffer.write(assembleDocument(shellHtml, meta.assets, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce));
|
|
691
|
+
buffer.write(assembleDocument(shellHtml, meta.assets, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
|
|
354
692
|
},
|
|
355
693
|
...options.sink
|
|
356
694
|
};
|
|
@@ -421,10 +759,28 @@ function renderToStream(code, options = {}) {
|
|
|
421
759
|
}
|
|
422
760
|
};
|
|
423
761
|
const tracking = createAssetTracking();
|
|
762
|
+
const headRegistry = createHeadRegistry();
|
|
763
|
+
let headScriptFlushed = false;
|
|
764
|
+
const emitHeadOps = (key, ops) => {
|
|
765
|
+
const payload = JSON.stringify(ops).replace(/</g, "\\u003C");
|
|
766
|
+
emitTask(`${!headScriptFlushed ? HEAD_SCRIPT : ""}(_$HY.hp=_$HY.hp||{})[${JSON.stringify(key)}]=${payload}`);
|
|
767
|
+
headScriptFlushed = true;
|
|
768
|
+
};
|
|
424
769
|
solidJs.sharedConfig.context = context = {
|
|
425
770
|
async: true,
|
|
426
771
|
assets: [],
|
|
427
772
|
nonce,
|
|
773
|
+
registerHeadTags(tags) {
|
|
774
|
+
registerHeadTags(headRegistry, context, tracking,
|
|
775
|
+
(markup, gateEntry) => {
|
|
776
|
+
if (!firstFlushed) {
|
|
777
|
+
headRegistry.eagerHtml += markup;
|
|
778
|
+
if (gateEntry) gateEntry.emitted = true;
|
|
779
|
+
} else if (!gateEntry || !tracking.currentBoundaryId) {
|
|
780
|
+
sink.asset("head-tag", markup);
|
|
781
|
+
}
|
|
782
|
+
}, nonce, tags);
|
|
783
|
+
},
|
|
428
784
|
registerAsset(type, value) {
|
|
429
785
|
if (type === "inline-style") {
|
|
430
786
|
const entry = tracking.registerInlineStyle(value);
|
|
@@ -515,10 +871,12 @@ function renderToStream(code, options = {}) {
|
|
|
515
871
|
parent.children[key] = value !== undefined ? value : "";
|
|
516
872
|
serializeFragmentAssets(key, tracking.boundaryModules, context);
|
|
517
873
|
propagateBoundaryStyles(key, parentKey, tracking);
|
|
874
|
+
adoptHeadBoundary(headRegistry, key, parentKey);
|
|
518
875
|
item.resolve();
|
|
519
876
|
return;
|
|
520
877
|
}
|
|
521
878
|
if (!completed) {
|
|
879
|
+
if (error) dropHeadBoundary(headRegistry, key);
|
|
522
880
|
if (!firstFlushed) {
|
|
523
881
|
queue(() => html = replacePlaceholder(html, key, value !== undefined ? value : ""));
|
|
524
882
|
serializeFragmentAssets(key, tracking.boundaryModules, context);
|
|
@@ -526,6 +884,8 @@ function renderToStream(code, options = {}) {
|
|
|
526
884
|
} else {
|
|
527
885
|
serializeFragmentAssets(key, tracking.boundaryModules, context);
|
|
528
886
|
const styles = collectStreamStyles(key, tracking, headStyles);
|
|
887
|
+
const headOps = error ? null : flushHeadFragment(headRegistry, key);
|
|
888
|
+
if (headOps) emitHeadOps(key, headOps);
|
|
529
889
|
sink.fragment(key, value !== undefined ? value : " ", {
|
|
530
890
|
styles,
|
|
531
891
|
revealGroup,
|
|
@@ -613,14 +973,16 @@ function renderToStream(code, options = {}) {
|
|
|
613
973
|
const assetsHtml = resolveAssetsHtml(context.assets);
|
|
614
974
|
headStyles = new Set();
|
|
615
975
|
for (const url of tracking.emittedAssets) {
|
|
616
|
-
if (url
|
|
976
|
+
if (isCssUrl(url)) headStyles.add(url);
|
|
617
977
|
}
|
|
618
978
|
serializeRootAssets();
|
|
979
|
+
const head = renderShellHead(headRegistry, nonce, k => registry.has(k));
|
|
619
980
|
sink.shell(html, {
|
|
620
981
|
assets: assetsHtml,
|
|
621
982
|
preloads: tracking.emittedAssets,
|
|
622
983
|
inlineStyles: tracking.inlineStyles,
|
|
623
|
-
tasks
|
|
984
|
+
tasks,
|
|
985
|
+
head
|
|
624
986
|
});
|
|
625
987
|
tasks = "";
|
|
626
988
|
onCompleteShell && onCompleteShell({
|
|
@@ -1006,23 +1368,42 @@ function resolveAssetsHtml(assets) {
|
|
|
1006
1368
|
for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
|
|
1007
1369
|
return out;
|
|
1008
1370
|
}
|
|
1009
|
-
function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts, nonce) {
|
|
1371
|
+
function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
|
|
1010
1372
|
const scriptTag = scripts ? `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>` : "";
|
|
1011
|
-
|
|
1373
|
+
const headTagsHtml = headTags ? headTags.html : "";
|
|
1374
|
+
const headPrelude = headTags ? headTags.prelude : "";
|
|
1375
|
+
if (!onHead && !assetsHtml && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
|
|
1012
1376
|
if (!scriptTag) return html;
|
|
1013
1377
|
const xs = html.indexOf("<!--xs-->");
|
|
1014
1378
|
return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
|
|
1015
1379
|
}
|
|
1380
|
+
if (headPrelude) {
|
|
1381
|
+
const open = html.match(/<head(?:\s[^>]*)?>/);
|
|
1382
|
+
if (open) {
|
|
1383
|
+
const at = open.index + open[0].length;
|
|
1384
|
+
html = html.slice(0, at) + headPrelude + html.slice(at);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1016
1387
|
const headIdx = html.indexOf("</head>");
|
|
1017
1388
|
if (headIdx === -1) {
|
|
1389
|
+
if (onHead) {
|
|
1390
|
+
onHead(headPrelude + headTagsHtml + (assetsHtml || "") + renderHeadAssets(emittedAssets, inlineStyles, nonce));
|
|
1391
|
+
}
|
|
1018
1392
|
if (!scriptTag) return html;
|
|
1019
1393
|
const xs = html.indexOf("<!--xs-->");
|
|
1020
1394
|
return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
|
|
1021
1395
|
}
|
|
1022
|
-
|
|
1396
|
+
const head = headTagsHtml + (assetsHtml || "") + renderHeadAssets(emittedAssets, inlineStyles, nonce);
|
|
1397
|
+
if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
|
|
1398
|
+
const xsIdx = html.indexOf("<!--xs-->");
|
|
1399
|
+
if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
|
|
1400
|
+
return xsIdx < headIdx ? html.slice(0, xsIdx) + scriptTag + html.slice(xsIdx, headIdx) + head + html.slice(headIdx) : html.slice(0, headIdx) + head + html.slice(headIdx, xsIdx) + scriptTag + html.slice(xsIdx);
|
|
1401
|
+
}
|
|
1402
|
+
function renderHeadAssets(emittedAssets, inlineStyles, nonce) {
|
|
1403
|
+
let head = "";
|
|
1023
1404
|
if (emittedAssets && emittedAssets.size) {
|
|
1024
1405
|
for (const url of emittedAssets) {
|
|
1025
|
-
head += url
|
|
1406
|
+
head += isCssUrl(url) ? `<link rel="stylesheet" href="${url}">` : `<link rel="modulepreload" href="${url}">`;
|
|
1026
1407
|
}
|
|
1027
1408
|
}
|
|
1028
1409
|
if (inlineStyles && inlineStyles.size) {
|
|
@@ -1032,10 +1413,7 @@ function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts
|
|
|
1032
1413
|
head += renderInlineStyle(entry, nonce);
|
|
1033
1414
|
}
|
|
1034
1415
|
}
|
|
1035
|
-
|
|
1036
|
-
const xsIdx = html.indexOf("<!--xs-->");
|
|
1037
|
-
if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
|
|
1038
|
-
return xsIdx < headIdx ? html.slice(0, xsIdx) + scriptTag + html.slice(xsIdx, headIdx) + head + html.slice(headIdx) : html.slice(0, headIdx) + head + html.slice(headIdx, xsIdx) + scriptTag + html.slice(xsIdx);
|
|
1416
|
+
return head;
|
|
1039
1417
|
}
|
|
1040
1418
|
function serializeFragmentAssets(key, boundaryModules, context) {
|
|
1041
1419
|
const map = boundaryModules.get(key);
|
|
@@ -1065,7 +1443,12 @@ function collectStreamStyles(key, tracking, headStyles) {
|
|
|
1065
1443
|
for (const entry of styles) {
|
|
1066
1444
|
if (typeof entry === "string") {
|
|
1067
1445
|
if (!headStyles || !headStyles.has(entry)) links.push(entry);
|
|
1068
|
-
} else if (
|
|
1446
|
+
} else if (entry.emitted) {
|
|
1447
|
+
continue;
|
|
1448
|
+
} else if (entry.attrHtml !== undefined) {
|
|
1449
|
+
entry.emitted = true;
|
|
1450
|
+
links.push(entry);
|
|
1451
|
+
} else {
|
|
1069
1452
|
entry.emitted = true;
|
|
1070
1453
|
inline.push(entry);
|
|
1071
1454
|
}
|
|
@@ -1462,7 +1845,12 @@ function createFrameSink(emit, frame) {
|
|
|
1462
1845
|
version,
|
|
1463
1846
|
key
|
|
1464
1847
|
};
|
|
1465
|
-
if (links.length)
|
|
1848
|
+
if (links.length) {
|
|
1849
|
+
chunk.styles = links.map(e => typeof e === "string" ? e : e.attrs ? {
|
|
1850
|
+
href: e.href,
|
|
1851
|
+
attrs: e.attrs
|
|
1852
|
+
} : e.href);
|
|
1853
|
+
}
|
|
1466
1854
|
if (inline.length) {
|
|
1467
1855
|
chunk.inlineStyles = inline.map(e => ({
|
|
1468
1856
|
id: e.id,
|