Blog
captureDOM function in snapDOM codebase - part 1

captureDOM function in snapDOM codebase - part 1

In this article, we review captureDOM function in snapDOM codebase. This review is split into 2 parts. We will look at:

  1. captureDOM overview

  2. options

  3. prepareClone function

  4. inlineImages function

  5. inlineBackgroundImages function

captureDOM overview

capture.js has 129 LOC at the time of writing this article. captureDOM is a core function in snapDOM.

This function gets called when you call snapdom.capture function as shown below:

snapdom.capture = async (el, options = {}) => {
  const url = await captureDOM(el, options);

This above code snippet is picked from snapdom.js.

options

The following are the available options passed as a parameter to the captureDOM function

  const { compress = true, embedFonts = false, fast = true, scale = 1, useProxy = ''} = options;

For a comprehensive list of supported options, check out the docs.

prepareClone function

The following code is picked from snapdom/src/core/prepare.js:

/**
 * Prepares a clone of an element for capture, inlining pseudo-elements and generating CSS classes.
 *
 * @param {Element} element - Element to clone
 * @param {boolean} [compress=false] - Whether to compress style keys
 * @param {boolean} [embedFonts=false] - Whether to embed custom fonts
 * @param {Object} [options={}] - Capture options
 * @param {string[]} [options.exclude] - CSS selectors for elements to exclude
 * @param {Function} [options.filter] - Custom filter function
 * @returns {Promise<Object>} Object containing the clone, generated CSS, and style cache
 */

export async function prepareClone(element, compress = false, embedFonts = false, options = {}) {
 ...
}

This function has a comment explaining what it does, along with the parameters description.

inlineImages function

The following code is picked from images.js

/**
 * Converts all <img> elements in the clone to data URLs or replaces them with placeholders if loading fails.
 *
 * @param {Element} clone - Clone of the original element
 * @param {Object} [options={}] - Options for image processing
 * @returns {Promise<void>} Promise that resolves when all images are processed
 */
export async function inlineImages(clone, options = {}) {
  const imgs = Array.from(clone.querySelectorAll("img"));
  const processImg = async (img) => {
    const src = img.src;
    try {
      const dataUrl = await fetchImage(src, { useProxy: options.useProxy });
      img.src = dataUrl;
      if (!img.width) img.width = img.naturalWidth || 100;
      if (!img.height) img.height = img.naturalHeight || 100;
    } catch {
      const fallback = document.createElement("div");
      fallback.style = `width: ${img.width || 100}px; height: ${img.height || 100}px; background: #ccc; display: inline-block; text-align: center; line-height: ${img.height || 100}px; color: #666; font-size: 12px;`;
      fallback.innerText = "img";
      img.replaceWith(fallback);
    }
  };
  for (let i = 0; i < imgs.length; i += 4) {
    const group = imgs.slice(i, i + 4).map(processImg);
    await Promise.allSettled(group);
  }
}

This function converts an image to data URL and if the image loading fails, it shows a placeholder in the image captured as a fallback.

inlineBackgroundImages function

The following code is picked from modules/background.js

/**
 * Recursively inlines background-related images and masks from the source element to its clone.
 * 
 * This function walks through the source DOM tree and its clone, copying inline styles for
 * background images, masks, and border images to ensure the clone retains all visual image
 * resources inline (e.g., data URLs), avoiding external dependencies.
 * 
 * It also preserves the `background-color` property if it is not transparent.
 * 
 * Special handling is done for `border-image` related properties: the
 * `border-image-slice`, `border-image-width`, `border-image-outset`, and `border-image-repeat`
 * are only copied if `border-image` or `border-image-source` are present and active.
 * 
 * @param {HTMLElement} source The original source element from which styles are read.
 * @param {HTMLElement} clone The cloned element to which inline styles are applied.
 * @param {Object} [options={}] Optional parameters passed to image inlining functions.
 * @returns {Promise<void>} Resolves when all inlining operations (including async image fetches) complete.
 */
export async function inlineBackgroundImages(source, clone, options = {}) {
 ...
}

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: ramu.narasinga@gmail.com

Want to learn from open-source? Solve challenges inspired by open-source projects.

References:

  1. https://github.com/zumerlab/snapdom/blob/main/src/core/capture.js#L28

  2. https://github.com/zumerlab/snapdom/blob/main/src/api/snapdom.js#L261

  3. https://github.com/zumerlab/snapdom?tab=readme-ov-file#options

  4. https://github.com/zumerlab/snapdom/blob/main/src/core/prepare.js#L25

  5. https://github.com/zumerlab/snapdom/blob/main/src/modules/images.js#L15

  6. https://github.com/zumerlab/snapdom/blob/main/src/modules/background.js#L26