diff --git a/README.md b/README.md index a18a2a8b..13992d9f 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,23 @@ htmlToImage }); ``` +#### clearCaches +For single-page applications that rely heavily on image generation, you can use the `clearCaches` method between navigations to free up memory held by cached resources. + +```js +// all caches +htmlToImage + .clearCaches(); + +// images cache only +htmlToImage + .clearCaches(htmlToImage.CacheType.IMAGES); + +// fonts cache only +htmlToImage + .clearCaches(htmlToImage.CacheType.FONTS); +``` + #### React ```tsx import React, { useCallback, useRef } from 'react'; @@ -193,7 +210,7 @@ const App: React.FC = () => { A function taking DOM node as argument. Should return true if passed node should be included in the output. Excluding node means excluding it's children as well. -You can add filter to every image function. For example, +You can add filter to every image function. For example, ```ts const filter = (node: HTMLElement) => { @@ -289,12 +306,12 @@ html2Image.toSVG(element2, { fontEmbedCSS }); When supplied, the library will skip the process of scaling extra large doms into the canvas object. You may experience loss of parts of the image if set to `true` and you are exporting a very large image. -Defaults to `false` +Defaults to `false` ### type A string indicating the image format. The default type is image/png; that type is also used if the given type isn't supported. -When supplied, the toCanvas function will return a blob matching the given image type and quality. +When supplied, the toCanvas function will return a blob matching the given image type and quality. Defaults to `image/png` @@ -320,7 +337,7 @@ There might some day exist (or maybe already exists?) a simple and standard way This library uses a feature of SVG that allows having arbitrary HTML content inside of the `` tag. So, in order to render that DOM node for you, following steps are taken: 1. Clone the original DOM node recursively -2. Compute the style for the node and each sub-node and copy it to corresponding clone +2. Compute the style for the node and each sub-node and copy it to corresponding clone - and don't forget to recreate pseudo-elements, as they are not cloned in any way, of course 3. Embed web fonts - find all the `@font-face` declarations that might represent web fonts diff --git a/src/dataurl.ts b/src/dataurl.ts index 13bc8b43..0f8b1be0 100644 --- a/src/dataurl.ts +++ b/src/dataurl.ts @@ -37,7 +37,7 @@ export async function fetchAsDataURL( }) } -const cache: { [url: string]: string } = {} +let cache: { [url: string]: string } = {} function getCacheKey( url: string, @@ -58,6 +58,10 @@ function getCacheKey( return contentType ? `[${contentType}]${key}` : key } +export function clearCache() { + cache = {} +} + export async function resourceToDataURL( resourceUrl: string, contentType: string | undefined, diff --git a/src/embed-images.ts b/src/embed-images.ts index 0d7b51ad..3cb9b0ae 100644 --- a/src/embed-images.ts +++ b/src/embed-images.ts @@ -4,6 +4,8 @@ import { toArray, isInstanceOfElement } from './util' import { isDataUrl, resourceToDataURL } from './dataurl' import { getMimeType } from './mimes' +export { clearCache } from './dataurl' + async function embedProp( propName: string, node: HTMLElement, diff --git a/src/embed-webfonts.ts b/src/embed-webfonts.ts index a84a699d..429ec1ba 100644 --- a/src/embed-webfonts.ts +++ b/src/embed-webfonts.ts @@ -8,7 +8,7 @@ interface Metadata { cssText: string } -const cssFetchCache: { [href: string]: Metadata } = {} +let cssFetchCache: { [href: string]: Metadata } = {} async function fetchCSS(url: string) { let cache = cssFetchCache[url] @@ -25,6 +25,10 @@ async function fetchCSS(url: string) { return cache } +export function clearCache() { + cssFetchCache = {} +} + async function embedFonts(data: Metadata, options: Options): Promise { let cssText = data.cssText const regexUrl = /url\(["']?([^"')]+)["']?\)/g diff --git a/src/index.ts b/src/index.ts index 2de59a30..14726717 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,12 @@ import { Options } from './types' import { cloneNode } from './clone-node' -import { embedImages } from './embed-images' +import { embedImages, clearCache as clearImagesCache } from './embed-images' import { applyStyle } from './apply-style' -import { embedWebFonts, getWebFontCSS } from './embed-webfonts' +import { + embedWebFonts, + getWebFontCSS, + clearCache as clearWebfontsCache, +} from './embed-webfonts' import { getImageSize, getPixelRatio, @@ -99,3 +103,19 @@ export async function getFontEmbedCSS( ): Promise { return getWebFontCSS(node, options) } + +export enum CacheType { + IMAGES, + FONTS, +} + +export function clearCaches(kind?: CacheType) { + const cacheToWiperMap = { + [CacheType.IMAGES]: clearImagesCache, + [CacheType.FONTS]: clearWebfontsCache, + } + const cachesToClear = + kind === undefined ? [CacheType.FONTS, CacheType.IMAGES] : [kind] + + cachesToClear.forEach((c) => cacheToWiperMap[c]()) +}