File size: 2,156 Bytes
fb38ec5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { JSDOM } from "jsdom";

export const transformHtml = (htmlContent: string, baseUrl?: string): string => {
  const dom = new JSDOM(htmlContent);
  const document = dom.window.document;

  optimizeImages(document);

  if (baseUrl) {
    normalizeUrls(document, baseUrl);
  }

  return document.documentElement.outerHTML;
};

const optimizeImages = (document: Document) => {
  const imagesWithSrcset = document.querySelectorAll("img[srcset]");

  imagesWithSrcset.forEach((img) => {
    const element = img as HTMLImageElement;
    const srcsetValue = element.getAttribute("srcset");
    if (!srcsetValue) return;

    const imageSources = srcsetValue.split(",").map((entry) => {
      const parts = entry.trim().split(" ");
      return {
        url: parts[0],
        size: parseInt((parts[1] ?? "1x").slice(0, -1), 10),
        isPixelDensity: (parts[1] ?? "").endsWith("x"),
      };
    });

    const currentSrc = element.getAttribute("src");
    if (imageSources.every((source) => source.isPixelDensity) && currentSrc) {
      imageSources.push({
        url: currentSrc,
        size: 1,
        isPixelDensity: true,
      });
    }

    imageSources.sort((a, b) => b.size - a.size);

    const bestSource = imageSources[0];
    if (bestSource) {
      element.setAttribute("src", bestSource.url);
      element.removeAttribute("srcset");
    }
  });
};

const normalizeUrls = (document: Document, baseUrl: string) => {
  try {
    const urlBase = new URL(baseUrl);

    const processElements = (selector: string, attribute: string) => {
      const elements = document.querySelectorAll(selector);
      elements.forEach((element) => {
        try {
          const currentValue = element.getAttribute(attribute);
          if (currentValue) {
            element.setAttribute(attribute, new URL(currentValue, urlBase).href);
          }
        } catch {}
      });
    };

    processElements("img[src]", "src");
    processElements("a[href]", "href");
    processElements("link[href]", "href");
    processElements("video[src]", "src");
    processElements("audio[src]", "src");
    processElements("source[src]", "src");
  } catch {}
};