@zumer/snapdom 1.9.3 → 1.9.6-dev.0
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/README.md +36 -34
- package/dist/snapdom.js +165 -143
- package/dist/snapdom.min.js +7 -7
- package/dist/snapdom.min.mjs +10 -10
- package/dist/snapdom.mjs +163 -141
- package/package.json +1 -1
- package/types/snapdom.d.ts +1 -0
package/dist/snapdom.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
3
|
* snapdom
|
|
4
|
-
* v.1.9.
|
|
4
|
+
* v.1.9.6-dev.0
|
|
5
5
|
* Author Juan Martin Muda
|
|
6
6
|
* License MIT
|
|
7
7
|
**/
|
|
@@ -57,13 +57,29 @@
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
// src/core/cache.js
|
|
60
|
-
var
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
var cache = {
|
|
61
|
+
image: /* @__PURE__ */ new Map(),
|
|
62
|
+
background: /* @__PURE__ */ new Map(),
|
|
63
|
+
resource: /* @__PURE__ */ new Map(),
|
|
64
|
+
defaultStyle: /* @__PURE__ */ new Map(),
|
|
65
|
+
baseStyle: /* @__PURE__ */ new Map(),
|
|
66
|
+
computedStyle: /* @__PURE__ */ new WeakMap(),
|
|
67
|
+
font: /* @__PURE__ */ new Set(),
|
|
68
|
+
snapshot: /* @__PURE__ */ new WeakMap(),
|
|
69
|
+
snapshotKey: /* @__PURE__ */ new Map(),
|
|
70
|
+
preStyleMap: /* @__PURE__ */ new Map(),
|
|
71
|
+
preStyle: /* @__PURE__ */ new WeakMap(),
|
|
72
|
+
preNodeMap: /* @__PURE__ */ new Map(),
|
|
73
|
+
reset: resetCache
|
|
74
|
+
};
|
|
75
|
+
function resetCache() {
|
|
76
|
+
cache.computedStyle = /* @__PURE__ */ new WeakMap();
|
|
77
|
+
cache.snapshot = /* @__PURE__ */ new WeakMap();
|
|
78
|
+
cache.snapshotKey.clear();
|
|
79
|
+
cache.preStyleMap.clear();
|
|
80
|
+
cache.preStyle = /* @__PURE__ */ new WeakMap();
|
|
81
|
+
cache.preNodeMap.clear();
|
|
82
|
+
}
|
|
67
83
|
|
|
68
84
|
// src/utils/cssTools.js
|
|
69
85
|
var commonTags = [
|
|
@@ -111,13 +127,13 @@
|
|
|
111
127
|
}
|
|
112
128
|
}
|
|
113
129
|
function getDefaultStyleForTag(tagName) {
|
|
114
|
-
if (
|
|
115
|
-
return
|
|
130
|
+
if (cache.defaultStyle.has(tagName)) {
|
|
131
|
+
return cache.defaultStyle.get(tagName);
|
|
116
132
|
}
|
|
117
133
|
const skipTags = /* @__PURE__ */ new Set(["script", "style", "meta", "link", "noscript", "template"]);
|
|
118
134
|
if (skipTags.has(tagName)) {
|
|
119
135
|
const empty = {};
|
|
120
|
-
|
|
136
|
+
cache.defaultStyle.set(tagName, empty);
|
|
121
137
|
return empty;
|
|
122
138
|
}
|
|
123
139
|
let sandbox = document.getElementById("snapdom-sandbox");
|
|
@@ -141,7 +157,7 @@
|
|
|
141
157
|
defaults[prop] = styles.getPropertyValue(prop);
|
|
142
158
|
}
|
|
143
159
|
sandbox.removeChild(el);
|
|
144
|
-
|
|
160
|
+
cache.defaultStyle.set(tagName, defaults);
|
|
145
161
|
return defaults;
|
|
146
162
|
}
|
|
147
163
|
function getStyleKey(snapshot, tagName, compress = false) {
|
|
@@ -177,7 +193,7 @@
|
|
|
177
193
|
function generateDedupedBaseCSS(usedTagNames) {
|
|
178
194
|
const groups = /* @__PURE__ */ new Map();
|
|
179
195
|
for (let tagName of usedTagNames) {
|
|
180
|
-
const styles =
|
|
196
|
+
const styles = cache.defaultStyle.get(tagName);
|
|
181
197
|
if (!styles) continue;
|
|
182
198
|
const key = Object.entries(styles).map(([k, v]) => `${k}:${v};`).sort().join("");
|
|
183
199
|
if (!groups.has(key)) {
|
|
@@ -192,8 +208,8 @@
|
|
|
192
208
|
}
|
|
193
209
|
return css;
|
|
194
210
|
}
|
|
195
|
-
function generateCSSClasses(
|
|
196
|
-
const keySet = new Set(
|
|
211
|
+
function generateCSSClasses() {
|
|
212
|
+
const keySet = new Set(cache.preStyleMap.values());
|
|
197
213
|
const classMap = /* @__PURE__ */ new Map();
|
|
198
214
|
let counter = 1;
|
|
199
215
|
for (const key of keySet) {
|
|
@@ -205,17 +221,15 @@
|
|
|
205
221
|
// src/utils/helpers.js
|
|
206
222
|
function inlineSingleBackgroundEntry(_0) {
|
|
207
223
|
return __async(this, arguments, function* (entry, options = {}) {
|
|
208
|
-
const
|
|
224
|
+
const rawUrl = extractURL(entry);
|
|
209
225
|
const isGradient = /^((repeating-)?(linear|radial|conic)-gradient)\(/i.test(entry);
|
|
210
|
-
if (
|
|
211
|
-
const rawUrl = extractURL(entry);
|
|
212
|
-
if (!rawUrl) return entry;
|
|
226
|
+
if (rawUrl) {
|
|
213
227
|
const encodedUrl = safeEncodeURI(rawUrl);
|
|
214
|
-
if (
|
|
215
|
-
return options.skipInline ? void 0 : `url(${
|
|
228
|
+
if (cache.background.has(encodedUrl)) {
|
|
229
|
+
return options.skipInline ? void 0 : `url(${cache.background.get(encodedUrl)})`;
|
|
216
230
|
} else {
|
|
217
231
|
const dataUrl = yield fetchImage(encodedUrl, { useProxy: options.useProxy });
|
|
218
|
-
|
|
232
|
+
cache.background.set(encodedUrl, dataUrl);
|
|
219
233
|
return options.skipInline ? void 0 : `url("${dataUrl}")`;
|
|
220
234
|
}
|
|
221
235
|
}
|
|
@@ -237,10 +251,10 @@
|
|
|
237
251
|
if (!(el instanceof Element)) {
|
|
238
252
|
return window.getComputedStyle(el, pseudo);
|
|
239
253
|
}
|
|
240
|
-
let map =
|
|
254
|
+
let map = cache.computedStyle.get(el);
|
|
241
255
|
if (!map) {
|
|
242
256
|
map = /* @__PURE__ */ new Map();
|
|
243
|
-
|
|
257
|
+
cache.computedStyle.set(el, map);
|
|
244
258
|
}
|
|
245
259
|
if (!map.has(pseudo)) {
|
|
246
260
|
const st = window.getComputedStyle(el, pseudo);
|
|
@@ -316,13 +330,13 @@
|
|
|
316
330
|
}
|
|
317
331
|
const crossOriginValue = getCrossOriginMode(src);
|
|
318
332
|
console.log(`[SnapDOM - fetchImage] Start loading image: ${src} with crossOrigin=${crossOriginValue}`);
|
|
319
|
-
if (
|
|
333
|
+
if (cache.image.has(src)) {
|
|
320
334
|
console.log(`[SnapDOM - fetchImage] Cache hit for: ${src}`);
|
|
321
|
-
return Promise.resolve(
|
|
335
|
+
return Promise.resolve(cache.image.get(src));
|
|
322
336
|
}
|
|
323
337
|
const isDataURI = src.startsWith("data:image/");
|
|
324
338
|
if (isDataURI) {
|
|
325
|
-
|
|
339
|
+
cache.image.set(src, src);
|
|
326
340
|
return Promise.resolve(src);
|
|
327
341
|
}
|
|
328
342
|
const isSVG = /\.svg(\?.*)?$/i.test(src);
|
|
@@ -335,7 +349,7 @@
|
|
|
335
349
|
});
|
|
336
350
|
const svgText = yield response.text();
|
|
337
351
|
const encoded = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgText)}`;
|
|
338
|
-
|
|
352
|
+
cache.image.set(src, encoded);
|
|
339
353
|
return encoded;
|
|
340
354
|
} catch (e) {
|
|
341
355
|
return fetchWithFallback(src);
|
|
@@ -359,12 +373,12 @@
|
|
|
359
373
|
const ctx = canvas.getContext("2d");
|
|
360
374
|
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
361
375
|
const dataURL = canvas.toDataURL("image/png");
|
|
362
|
-
|
|
376
|
+
cache.image.set(src, dataURL);
|
|
363
377
|
resolve(dataURL);
|
|
364
378
|
} catch (e) {
|
|
365
379
|
try {
|
|
366
380
|
const fallbackDataURL = yield fetchWithFallback(src);
|
|
367
|
-
|
|
381
|
+
cache.image.set(src, fallbackDataURL);
|
|
368
382
|
resolve(fallbackDataURL);
|
|
369
383
|
} catch (e2) {
|
|
370
384
|
reject(e2);
|
|
@@ -376,7 +390,7 @@
|
|
|
376
390
|
console.error(`[SnapDOM - fetchImage] Image failed to load: ${src}`);
|
|
377
391
|
try {
|
|
378
392
|
const fallbackDataURL = yield fetchWithFallback(src);
|
|
379
|
-
|
|
393
|
+
cache.image.set(src, fallbackDataURL);
|
|
380
394
|
resolve(fallbackDataURL);
|
|
381
395
|
} catch (e) {
|
|
382
396
|
reject(e);
|
|
@@ -440,8 +454,6 @@
|
|
|
440
454
|
}
|
|
441
455
|
|
|
442
456
|
// src/modules/styles.js
|
|
443
|
-
var snapshotCache = /* @__PURE__ */ new WeakMap();
|
|
444
|
-
var snapshotKeyCache = /* @__PURE__ */ new Map();
|
|
445
457
|
function snapshotComputedStyleFull(style) {
|
|
446
458
|
const result = {};
|
|
447
459
|
for (let i = 0; i < style.length; i++) {
|
|
@@ -454,37 +466,36 @@
|
|
|
454
466
|
}
|
|
455
467
|
return result;
|
|
456
468
|
}
|
|
457
|
-
function inlineAllStyles(source, clone,
|
|
469
|
+
function inlineAllStyles(source, clone, compress) {
|
|
458
470
|
var _a;
|
|
459
471
|
if (source.tagName === "STYLE") return;
|
|
460
|
-
if (!cache.has(source)) {
|
|
461
|
-
cache.set(source, getStyle(source));
|
|
472
|
+
if (!cache.preStyle.has(source)) {
|
|
473
|
+
cache.preStyle.set(source, getStyle(source));
|
|
462
474
|
}
|
|
463
|
-
const style = cache.get(source);
|
|
464
|
-
if (!
|
|
475
|
+
const style = cache.preStyle.get(source);
|
|
476
|
+
if (!cache.snapshot.has(source)) {
|
|
465
477
|
const snapshot2 = snapshotComputedStyleFull(style);
|
|
466
|
-
|
|
478
|
+
cache.snapshot.set(source, snapshot2);
|
|
467
479
|
}
|
|
468
|
-
const snapshot =
|
|
480
|
+
const snapshot = cache.snapshot.get(source);
|
|
469
481
|
const hash = Object.entries(snapshot).sort(([a], [b]) => a.localeCompare(b)).map(([prop, val]) => `${prop}:${val}`).join(";");
|
|
470
|
-
if (
|
|
471
|
-
|
|
482
|
+
if (cache.snapshotKey.has(hash)) {
|
|
483
|
+
cache.preStyleMap.set(clone, cache.snapshotKey.get(hash));
|
|
472
484
|
return;
|
|
473
485
|
}
|
|
474
486
|
const tagName = ((_a = source.tagName) == null ? void 0 : _a.toLowerCase()) || "div";
|
|
475
487
|
const key = getStyleKey(snapshot, tagName, compress);
|
|
476
|
-
|
|
477
|
-
|
|
488
|
+
cache.snapshotKey.set(hash, key);
|
|
489
|
+
cache.preStyleMap.set(clone, key);
|
|
478
490
|
}
|
|
479
491
|
|
|
480
492
|
// src/core/clone.js
|
|
481
|
-
function
|
|
482
|
-
|
|
493
|
+
function isSlotElement(node) {
|
|
494
|
+
return node.nodeType === Node.ELEMENT_NODE && node.tagName === "SLOT";
|
|
495
|
+
}
|
|
496
|
+
function deepClone(node, compress, options = {}, originalRoot) {
|
|
497
|
+
var _a, _b;
|
|
483
498
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
484
|
-
if ((_a = node.parentElement) == null ? void 0 : _a.shadowRoot) {
|
|
485
|
-
const tag = node.parentElement.tagName.toLowerCase();
|
|
486
|
-
if (customElements.get(tag)) return null;
|
|
487
|
-
}
|
|
488
499
|
return node.cloneNode(true);
|
|
489
500
|
}
|
|
490
501
|
if (node.nodeType !== Node.ELEMENT_NODE) return node.cloneNode(true);
|
|
@@ -494,10 +505,10 @@
|
|
|
494
505
|
spacer.style.cssText = `display: inline-block; width: ${rect.width}px; height: ${rect.height}px; visibility: hidden;`;
|
|
495
506
|
return spacer;
|
|
496
507
|
}
|
|
497
|
-
if (options.exclude && Array.isArray(options.exclude)
|
|
508
|
+
if (options.exclude && Array.isArray(options.exclude)) {
|
|
498
509
|
for (const selector of options.exclude) {
|
|
499
510
|
try {
|
|
500
|
-
if (node.matches
|
|
511
|
+
if ((_a = node.matches) == null ? void 0 : _a.call(node, selector)) {
|
|
501
512
|
const spacer = document.createElement("div");
|
|
502
513
|
const rect = node.getBoundingClientRect();
|
|
503
514
|
spacer.style.cssText = `display: inline-block; width: ${rect.width}px; height: ${rect.height}px; visibility: hidden;`;
|
|
@@ -528,8 +539,8 @@
|
|
|
528
539
|
}
|
|
529
540
|
if (node.getAttribute("data-capture") === "placeholder") {
|
|
530
541
|
const clone2 = node.cloneNode(false);
|
|
531
|
-
|
|
532
|
-
inlineAllStyles(node, clone2,
|
|
542
|
+
cache.preNodeMap.set(clone2, node);
|
|
543
|
+
inlineAllStyles(node, clone2, compress);
|
|
533
544
|
const placeholder = document.createElement("div");
|
|
534
545
|
placeholder.textContent = node.getAttribute("data-placeholder-text") || "";
|
|
535
546
|
placeholder.style.cssText = `color: #666;font-size: 12px;text-align: center;line-height: 1.4;padding: 0.5em;box-sizing: border-box;`;
|
|
@@ -548,7 +559,7 @@
|
|
|
548
559
|
return img;
|
|
549
560
|
}
|
|
550
561
|
const clone = node.cloneNode(false);
|
|
551
|
-
|
|
562
|
+
cache.preNodeMap.set(clone, node);
|
|
552
563
|
if (node instanceof HTMLInputElement) {
|
|
553
564
|
clone.value = node.value;
|
|
554
565
|
clone.setAttribute("value", node.value);
|
|
@@ -557,8 +568,10 @@
|
|
|
557
568
|
if (node.checked) clone.setAttribute("checked", "");
|
|
558
569
|
}
|
|
559
570
|
} else if (node instanceof HTMLTextAreaElement) {
|
|
560
|
-
|
|
571
|
+
const rect = node.getBoundingClientRect();
|
|
561
572
|
clone.textContent = node.value;
|
|
573
|
+
clone.style.width = `${rect.width}px`;
|
|
574
|
+
clone.style.height = `${rect.height}px`;
|
|
562
575
|
} else if (node instanceof HTMLSelectElement) {
|
|
563
576
|
clone.value = node.value;
|
|
564
577
|
Array.from(clone.options).forEach((opt) => {
|
|
@@ -569,19 +582,31 @@
|
|
|
569
582
|
}
|
|
570
583
|
});
|
|
571
584
|
}
|
|
572
|
-
inlineAllStyles(node, clone,
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
const
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
+
inlineAllStyles(node, clone, compress);
|
|
586
|
+
if (isSlotElement(node)) {
|
|
587
|
+
const assigned = ((_b = node.assignedNodes) == null ? void 0 : _b.call(node, { flatten: true })) || [];
|
|
588
|
+
const nodesToClone = assigned.length > 0 ? assigned : Array.from(node.childNodes);
|
|
589
|
+
const fragment = document.createDocumentFragment();
|
|
590
|
+
for (const child of nodesToClone) {
|
|
591
|
+
const clonedChild = deepClone(child, compress, options, originalRoot || node);
|
|
592
|
+
if (clonedChild) fragment.appendChild(clonedChild);
|
|
593
|
+
}
|
|
594
|
+
return fragment;
|
|
595
|
+
} else if (node instanceof HTMLTextAreaElement) {
|
|
596
|
+
} else {
|
|
597
|
+
const baseChildren = node.shadowRoot ? node.shadowRoot.childNodes : node.childNodes;
|
|
598
|
+
for (const child of baseChildren) {
|
|
599
|
+
const clonedChild = deepClone(child, compress, options, originalRoot || node);
|
|
600
|
+
if (clonedChild) clone.appendChild(clonedChild);
|
|
601
|
+
}
|
|
602
|
+
if (node.shadowRoot && node.childNodes.length > 0 && !node.shadowRoot.querySelector("slot")) {
|
|
603
|
+
const lightDomContent = document.createDocumentFragment();
|
|
604
|
+
for (const child of node.childNodes) {
|
|
605
|
+
const clonedChild = deepClone(child, compress, options, originalRoot || node);
|
|
606
|
+
if (clonedChild) lightDomContent.appendChild(clonedChild);
|
|
607
|
+
}
|
|
608
|
+
clone.appendChild(lightDomContent);
|
|
609
|
+
}
|
|
585
610
|
}
|
|
586
611
|
return clone;
|
|
587
612
|
}
|
|
@@ -666,14 +691,14 @@
|
|
|
666
691
|
}
|
|
667
692
|
function embedCustomFonts() {
|
|
668
693
|
return __async(this, arguments, function* ({ preCached = false } = {}) {
|
|
669
|
-
if (
|
|
694
|
+
if (cache.resource.has("fonts-embed-css")) {
|
|
670
695
|
if (preCached) {
|
|
671
696
|
const style = document.createElement("style");
|
|
672
697
|
style.setAttribute("data-snapdom", "embedFonts");
|
|
673
|
-
style.textContent =
|
|
698
|
+
style.textContent = cache.resource.get("fonts-embed-css");
|
|
674
699
|
document.head.appendChild(style);
|
|
675
700
|
}
|
|
676
|
-
return
|
|
701
|
+
return cache.resource.get("fonts-embed-css");
|
|
677
702
|
}
|
|
678
703
|
const importRegex = /@import\s+url\(["']?([^"')]+)["']?\)/g;
|
|
679
704
|
const styleImports = [];
|
|
@@ -706,11 +731,11 @@
|
|
|
706
731
|
url = new URL(url, link.href).href;
|
|
707
732
|
}
|
|
708
733
|
if (isIconFont(url)) return null;
|
|
709
|
-
if (
|
|
710
|
-
|
|
711
|
-
return { original: match[0], inlined: `url(${
|
|
734
|
+
if (cache.resource.has(url)) {
|
|
735
|
+
cache.font.add(url);
|
|
736
|
+
return { original: match[0], inlined: `url(${cache.resource.get(url)})` };
|
|
712
737
|
}
|
|
713
|
-
if (
|
|
738
|
+
if (cache.font.has(url)) return null;
|
|
714
739
|
try {
|
|
715
740
|
const fontRes = yield fetch(url);
|
|
716
741
|
const blob = yield fontRes.blob();
|
|
@@ -719,8 +744,8 @@
|
|
|
719
744
|
reader.onload = () => resolve(reader.result);
|
|
720
745
|
reader.readAsDataURL(blob);
|
|
721
746
|
});
|
|
722
|
-
|
|
723
|
-
|
|
747
|
+
cache.resource.set(url, b64);
|
|
748
|
+
cache.font.add(url);
|
|
724
749
|
return { original: match[0], inlined: `url(${b64})` };
|
|
725
750
|
} catch (e) {
|
|
726
751
|
console.warn("[snapdom] Failed to fetch font resource:", url);
|
|
@@ -756,12 +781,12 @@
|
|
|
756
781
|
url = new URL(url, sheet.href || location.href).href;
|
|
757
782
|
}
|
|
758
783
|
if (isIconFont(url)) continue;
|
|
759
|
-
if (
|
|
760
|
-
|
|
761
|
-
inlinedSrc = inlinedSrc.replace(match[0], `url(${
|
|
784
|
+
if (cache.resource.has(url)) {
|
|
785
|
+
cache.font.add(url);
|
|
786
|
+
inlinedSrc = inlinedSrc.replace(match[0], `url(${cache.resource.get(url)})`);
|
|
762
787
|
continue;
|
|
763
788
|
}
|
|
764
|
-
if (
|
|
789
|
+
if (cache.font.has(url)) continue;
|
|
765
790
|
try {
|
|
766
791
|
const res = yield fetch(url);
|
|
767
792
|
const blob = yield res.blob();
|
|
@@ -770,8 +795,8 @@
|
|
|
770
795
|
reader.onload = () => resolve(reader.result);
|
|
771
796
|
reader.readAsDataURL(blob);
|
|
772
797
|
});
|
|
773
|
-
|
|
774
|
-
|
|
798
|
+
cache.resource.set(url, b64);
|
|
799
|
+
cache.font.add(url);
|
|
775
800
|
inlinedSrc = inlinedSrc.replace(match[0], `url(${b64})`);
|
|
776
801
|
} catch (e) {
|
|
777
802
|
console.warn("[snapdom] Failed to fetch font URL:", url);
|
|
@@ -796,10 +821,10 @@
|
|
|
796
821
|
if (isIconFont(font.family)) continue;
|
|
797
822
|
let b64 = font._snapdomSrc;
|
|
798
823
|
if (!b64.startsWith("data:")) {
|
|
799
|
-
if (
|
|
800
|
-
b64 =
|
|
801
|
-
|
|
802
|
-
} else if (!
|
|
824
|
+
if (cache.resource.has(font._snapdomSrc)) {
|
|
825
|
+
b64 = cache.resource.get(font._snapdomSrc);
|
|
826
|
+
cache.font.add(font._snapdomSrc);
|
|
827
|
+
} else if (!cache.font.has(font._snapdomSrc)) {
|
|
803
828
|
try {
|
|
804
829
|
const res = yield fetch(font._snapdomSrc);
|
|
805
830
|
const blob = yield res.blob();
|
|
@@ -808,8 +833,8 @@
|
|
|
808
833
|
reader.onload = () => resolve(reader.result);
|
|
809
834
|
reader.readAsDataURL(blob);
|
|
810
835
|
});
|
|
811
|
-
|
|
812
|
-
|
|
836
|
+
cache.resource.set(font._snapdomSrc, b64);
|
|
837
|
+
cache.font.add(font._snapdomSrc);
|
|
813
838
|
} catch (e) {
|
|
814
839
|
console.warn("[snapdom] Failed to fetch dynamic font src:", font._snapdomSrc);
|
|
815
840
|
continue;
|
|
@@ -826,7 +851,7 @@
|
|
|
826
851
|
}
|
|
827
852
|
}
|
|
828
853
|
if (finalCSS) {
|
|
829
|
-
|
|
854
|
+
cache.resource.set("fonts-embed-css", finalCSS);
|
|
830
855
|
if (preCached) {
|
|
831
856
|
const style = document.createElement("style");
|
|
832
857
|
style.setAttribute("data-snapdom", "embedFonts");
|
|
@@ -839,7 +864,7 @@
|
|
|
839
864
|
}
|
|
840
865
|
|
|
841
866
|
// src/modules/pseudo.js
|
|
842
|
-
function inlinePseudoElements(source, clone,
|
|
867
|
+
function inlinePseudoElements(source, clone, compress, embedFonts = false, useProxy) {
|
|
843
868
|
return __async(this, null, function* () {
|
|
844
869
|
if (!(source instanceof Element) || !(clone instanceof Element)) return;
|
|
845
870
|
for (const pseudo of ["::before", "::after", "::first-letter"]) {
|
|
@@ -864,7 +889,7 @@
|
|
|
864
889
|
span.dataset.snapdomPseudo = "::first-letter";
|
|
865
890
|
const snapshot = snapshotComputedStyle(style);
|
|
866
891
|
const key = getStyleKey(snapshot, "span", compress);
|
|
867
|
-
|
|
892
|
+
cache.preStyleMap.set(span, key);
|
|
868
893
|
const restNode = document.createTextNode(rest);
|
|
869
894
|
clone.replaceChild(restNode, textNode);
|
|
870
895
|
clone.insertBefore(span, restNode);
|
|
@@ -885,7 +910,7 @@
|
|
|
885
910
|
pseudoEl.dataset.snapdomPseudo = pseudo;
|
|
886
911
|
const snapshot = snapshotComputedStyle(style);
|
|
887
912
|
const key = getStyleKey(snapshot, "span", compress);
|
|
888
|
-
|
|
913
|
+
cache.preStyleMap.set(pseudoEl, key);
|
|
889
914
|
const isIconFont2 = isIconFont(fontFamily);
|
|
890
915
|
const cleanContent = parseContent(content);
|
|
891
916
|
if (isIconFont2 && cleanContent.length === 1) {
|
|
@@ -936,8 +961,6 @@
|
|
|
936
961
|
yield inlinePseudoElements(
|
|
937
962
|
sChildren[i],
|
|
938
963
|
cChildren[i],
|
|
939
|
-
styleMap,
|
|
940
|
-
styleCache,
|
|
941
964
|
compress,
|
|
942
965
|
embedFonts,
|
|
943
966
|
useProxy
|
|
@@ -980,18 +1003,15 @@
|
|
|
980
1003
|
function prepareClone(_0) {
|
|
981
1004
|
return __async(this, arguments, function* (element, compress = false, embedFonts = false, options = {}) {
|
|
982
1005
|
var _a;
|
|
983
|
-
|
|
984
|
-
const styleCache = /* @__PURE__ */ new WeakMap();
|
|
985
|
-
const nodeMap = /* @__PURE__ */ new Map();
|
|
986
|
-
let clone;
|
|
1006
|
+
let clone, classCSS;
|
|
987
1007
|
try {
|
|
988
|
-
clone = deepClone(element,
|
|
1008
|
+
clone = deepClone(element, compress, options, element);
|
|
989
1009
|
} catch (e) {
|
|
990
1010
|
console.warn("deepClone failed:", e);
|
|
991
1011
|
throw e;
|
|
992
1012
|
}
|
|
993
1013
|
try {
|
|
994
|
-
yield inlinePseudoElements(element, clone,
|
|
1014
|
+
yield inlinePseudoElements(element, clone, compress, embedFonts, options.useProxy);
|
|
995
1015
|
} catch (e) {
|
|
996
1016
|
console.warn("inlinePseudoElements failed:", e);
|
|
997
1017
|
}
|
|
@@ -1000,11 +1020,10 @@
|
|
|
1000
1020
|
} catch (e) {
|
|
1001
1021
|
console.warn("inlineExternalDef failed:", e);
|
|
1002
1022
|
}
|
|
1003
|
-
let classCSS = "";
|
|
1004
1023
|
if (compress) {
|
|
1005
|
-
const keyToClass = generateCSSClasses(
|
|
1024
|
+
const keyToClass = generateCSSClasses();
|
|
1006
1025
|
classCSS = Array.from(keyToClass.entries()).map(([key, className]) => `.${className}{${key}}`).join("");
|
|
1007
|
-
for (const [node, key] of
|
|
1026
|
+
for (const [node, key] of cache.preStyleMap.entries()) {
|
|
1008
1027
|
if (node.tagName === "STYLE") continue;
|
|
1009
1028
|
const className = keyToClass.get(key);
|
|
1010
1029
|
if (className) node.classList.add(className);
|
|
@@ -1013,12 +1032,12 @@
|
|
|
1013
1032
|
if (bgImage && bgImage !== "none") node.style.backgroundImage = bgImage;
|
|
1014
1033
|
}
|
|
1015
1034
|
} else {
|
|
1016
|
-
for (const [node, key] of
|
|
1035
|
+
for (const [node, key] of cache.preStyleMap.entries()) {
|
|
1017
1036
|
if (node.tagName === "STYLE") continue;
|
|
1018
1037
|
node.setAttribute("style", key.replace(/;/g, "; "));
|
|
1019
1038
|
}
|
|
1020
1039
|
}
|
|
1021
|
-
for (const [cloneNode, originalNode] of
|
|
1040
|
+
for (const [cloneNode, originalNode] of cache.preNodeMap.entries()) {
|
|
1022
1041
|
const scrollX = originalNode.scrollLeft;
|
|
1023
1042
|
const scrollY = originalNode.scrollTop;
|
|
1024
1043
|
const hasScroll = scrollX || scrollY;
|
|
@@ -1037,9 +1056,9 @@
|
|
|
1037
1056
|
cloneNode.appendChild(inner);
|
|
1038
1057
|
}
|
|
1039
1058
|
}
|
|
1040
|
-
if (element ===
|
|
1041
|
-
const computed =
|
|
1042
|
-
|
|
1059
|
+
if (element === cache.preNodeMap.get(clone)) {
|
|
1060
|
+
const computed = cache.preStyle.get(element) || window.getComputedStyle(element);
|
|
1061
|
+
cache.preStyle.set(element, computed);
|
|
1043
1062
|
const transform = stripTranslate(computed.transform);
|
|
1044
1063
|
clone.style.margin = "0";
|
|
1045
1064
|
clone.style.position = "static";
|
|
@@ -1052,13 +1071,13 @@
|
|
|
1052
1071
|
clone.style.clear = "none";
|
|
1053
1072
|
clone.style.transform = transform || "";
|
|
1054
1073
|
}
|
|
1055
|
-
for (const [cloneNode, originalNode] of
|
|
1074
|
+
for (const [cloneNode, originalNode] of cache.preNodeMap.entries()) {
|
|
1056
1075
|
if (originalNode.tagName === "PRE") {
|
|
1057
1076
|
cloneNode.style.marginTop = "0";
|
|
1058
1077
|
cloneNode.style.marginBlockStart = "0";
|
|
1059
1078
|
}
|
|
1060
1079
|
}
|
|
1061
|
-
return { clone, classCSS
|
|
1080
|
+
return { clone, classCSS };
|
|
1062
1081
|
});
|
|
1063
1082
|
}
|
|
1064
1083
|
|
|
@@ -1088,30 +1107,35 @@
|
|
|
1088
1107
|
}
|
|
1089
1108
|
|
|
1090
1109
|
// src/modules/background.js
|
|
1091
|
-
function inlineBackgroundImages(_0, _1
|
|
1092
|
-
return __async(this, arguments, function* (source, clone,
|
|
1110
|
+
function inlineBackgroundImages(_0, _1) {
|
|
1111
|
+
return __async(this, arguments, function* (source, clone, options = {}) {
|
|
1093
1112
|
const queue = [[source, clone]];
|
|
1113
|
+
const imageProps = [
|
|
1114
|
+
"background-image",
|
|
1115
|
+
"mask",
|
|
1116
|
+
"mask-image",
|
|
1117
|
+
"-webkit-mask-image",
|
|
1118
|
+
"mask-source",
|
|
1119
|
+
"mask-box-image-source",
|
|
1120
|
+
"mask-border-source",
|
|
1121
|
+
"-webkit-mask-box-image-source"
|
|
1122
|
+
];
|
|
1094
1123
|
while (queue.length) {
|
|
1095
1124
|
const [srcNode, cloneNode] = queue.shift();
|
|
1096
|
-
const style =
|
|
1097
|
-
if (!
|
|
1098
|
-
const
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
const
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
|
|
1125
|
+
const style = cache.preStyle.get(srcNode) || getStyle(srcNode);
|
|
1126
|
+
if (!cache.preStyle.has(srcNode)) cache.preStyle.set(srcNode, style);
|
|
1127
|
+
for (const prop of imageProps) {
|
|
1128
|
+
const val = style.getPropertyValue(prop);
|
|
1129
|
+
if (!val || val === "none") continue;
|
|
1130
|
+
const splits = splitBackgroundImage(val);
|
|
1131
|
+
const inlined = yield Promise.all(
|
|
1132
|
+
splits.map((entry) => inlineSingleBackgroundEntry(entry, options))
|
|
1133
|
+
);
|
|
1134
|
+
if (inlined.some((p) => p && p !== "none" && !/^url\(undefined/.test(p))) {
|
|
1135
|
+
cloneNode.style.setProperty(prop, inlined.join(", "));
|
|
1105
1136
|
}
|
|
1106
|
-
continue;
|
|
1107
|
-
}
|
|
1108
|
-
const bgSplits = splitBackgroundImage(bg);
|
|
1109
|
-
const newBgParts = yield Promise.all(
|
|
1110
|
-
bgSplits.map((entry) => inlineSingleBackgroundEntry(entry, options))
|
|
1111
|
-
);
|
|
1112
|
-
if (newBgParts.some((p) => p && p !== "none" && !/^url\(undefined\)/.test(p))) {
|
|
1113
|
-
cloneNode.style.backgroundImage = newBgParts.join(", ");
|
|
1114
1137
|
}
|
|
1138
|
+
const bgColor = style.getPropertyValue("background-color");
|
|
1115
1139
|
if (bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)") {
|
|
1116
1140
|
cloneNode.style.backgroundColor = bgColor;
|
|
1117
1141
|
}
|
|
@@ -1128,13 +1152,14 @@
|
|
|
1128
1152
|
function captureDOM(_0) {
|
|
1129
1153
|
return __async(this, arguments, function* (element, options = {}) {
|
|
1130
1154
|
if (!element) throw new Error("Element cannot be null or undefined");
|
|
1155
|
+
cache.reset();
|
|
1131
1156
|
const { compress = true, embedFonts = false, fast = true, scale = 1, useProxy = "" } = options;
|
|
1132
|
-
let clone, classCSS
|
|
1157
|
+
let clone, classCSS;
|
|
1133
1158
|
let fontsCSS = "";
|
|
1134
1159
|
let baseCSS = "";
|
|
1135
1160
|
let dataURL;
|
|
1136
1161
|
let svgString;
|
|
1137
|
-
({ clone, classCSS
|
|
1162
|
+
({ clone, classCSS } = yield prepareClone(element, compress, embedFonts, options));
|
|
1138
1163
|
yield new Promise((resolve) => {
|
|
1139
1164
|
idle(() => __async(null, null, function* () {
|
|
1140
1165
|
yield inlineImages(clone, options);
|
|
@@ -1143,7 +1168,7 @@
|
|
|
1143
1168
|
});
|
|
1144
1169
|
yield new Promise((resolve) => {
|
|
1145
1170
|
idle(() => __async(null, null, function* () {
|
|
1146
|
-
yield inlineBackgroundImages(element, clone,
|
|
1171
|
+
yield inlineBackgroundImages(element, clone, options);
|
|
1147
1172
|
resolve();
|
|
1148
1173
|
}), { fast });
|
|
1149
1174
|
});
|
|
@@ -1158,13 +1183,13 @@
|
|
|
1158
1183
|
if (compress) {
|
|
1159
1184
|
const usedTags = collectUsedTagNames(clone).sort();
|
|
1160
1185
|
const tagKey = usedTags.join(",");
|
|
1161
|
-
if (
|
|
1162
|
-
baseCSS =
|
|
1186
|
+
if (cache.baseStyle.has(tagKey)) {
|
|
1187
|
+
baseCSS = cache.baseStyle.get(tagKey);
|
|
1163
1188
|
} else {
|
|
1164
1189
|
yield new Promise((resolve) => {
|
|
1165
1190
|
idle(() => {
|
|
1166
1191
|
baseCSS = generateDedupedBaseCSS(usedTags);
|
|
1167
|
-
|
|
1192
|
+
cache.baseStyle.set(tagKey, baseCSS);
|
|
1168
1193
|
resolve();
|
|
1169
1194
|
}, { fast });
|
|
1170
1195
|
});
|
|
@@ -1406,10 +1431,7 @@
|
|
|
1406
1431
|
return __async(this, arguments, function* (root = document, options = {}) {
|
|
1407
1432
|
const { embedFonts = true, reset = false } = options;
|
|
1408
1433
|
if (reset) {
|
|
1409
|
-
|
|
1410
|
-
bgCache.clear();
|
|
1411
|
-
resourceCache.clear();
|
|
1412
|
-
baseCSSCache.clear();
|
|
1434
|
+
cache.reset();
|
|
1413
1435
|
return;
|
|
1414
1436
|
}
|
|
1415
1437
|
yield document.fonts.ready;
|
|
@@ -1422,9 +1444,9 @@
|
|
|
1422
1444
|
const promises = [];
|
|
1423
1445
|
for (const img of imgEls) {
|
|
1424
1446
|
const src = img.src;
|
|
1425
|
-
if (!
|
|
1447
|
+
if (!cache.image.has(src)) {
|
|
1426
1448
|
promises.push(
|
|
1427
|
-
fetchImage(src, { useProxy: options.useProxy }).then((dataURL) =>
|
|
1449
|
+
fetchImage(src, { useProxy: options.useProxy }).then((dataURL) => cache.image.set(src, dataURL)).catch(() => {
|
|
1428
1450
|
})
|
|
1429
1451
|
);
|
|
1430
1452
|
}
|