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:
-
captureDOM overview
-
options
-
prepareClone function
-
inlineImages function
-
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:
-
https://github.com/zumerlab/snapdom/blob/main/src/core/capture.js#L28
-
https://github.com/zumerlab/snapdom/blob/main/src/api/snapdom.js#L261
-
https://github.com/zumerlab/snapdom?tab=readme-ov-file#options
-
https://github.com/zumerlab/snapdom/blob/main/src/core/prepare.js#L25
-
https://github.com/zumerlab/snapdom/blob/main/src/modules/images.js#L15
-
https://github.com/zumerlab/snapdom/blob/main/src/modules/background.js#L26