npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@peaceroad/markdown-it-renderer-image

v0.10.0

Published

A markdown-it plugin. This add width and height attributes to img elements.

Readme

p7d-markdown-it-renderer-image

A markdown-it plugin plus a browser DOM helper to set img attributes (width/height, loading, decoding) and optionally resolve src using frontmatter.

Quick start

Node usage (markdown-it)

import fs from 'fs'
import mdit from 'markdown-it'
import mditRendererImage from '@peaceroad/markdown-it-renderer-image'

const mdFile = '/tmp/markdown.md'
const md = mdit().use(mditRendererImage, { mdPath: mdFile })
const mdCont = fs.readFileSync(mdFile, 'utf-8')

console.log(md.render(mdCont))

mdPath accepts either a markdown file path or a directory path. If a directory is provided, it is used as-is for local image resolution.

You can also pass mdPath via the render env:

const md = mdit().use(mditRendererImage)
console.log(md.render(mdCont, { mdPath: mdFile }))

Frontmatter-based rewriting on Node:

const frontmatter = { url: 'https://example.com/page' }
const html = md.render(mdCont, { mdPath: mdFile, frontmatter })
console.log(html)

Browser / DOM usage

<script type="module">
import { runInPreview, applyImageTransformsToString } from '<package>/script/set-img-attributes.js'

const { observer } = await runInPreview({
  root: document,
  markdownCont,
  readMeta: true, // read frontmatter from <meta>
  observe: true,  // start MutationObserver
})

// Process an HTML string (e.g. source view)
const transformed = await applyImageTransformsToString(htmlSource, { readMeta: true }, markdownCont)

// Stop observing when needed
observer?.disconnect()
</script>

Notes:

  • The DOM helper provides named functions; the default export is a no-op compatibility shim.
  • runInPreview({ root, markdownCont, observe, ...options }) is a high-level helper for preview flows (create context + apply + optional observer).
  • The default-export no-op returns a resolved Promise for safer .catch(...) chaining in accidental async usage.
  • The no-op warning is shown once in non-production. Set suppressNoopWarning: true to silence it.
  • In browser builds, importing the package root resolves to the DOM helper (named exports + no-op default). Use the script path if you want to be explicit.
  • Default option objects are exported (defaultSharedOptions, defaultDomOptions, defaultNodeOptions) to keep CLI and DOM configs in sync.
  • createContext reads YAML frontmatter from the first argument (markdown text). Pass null/'' to skip YAML parsing and rely on readMeta (JSON in meta[name="markdown-frontmatter"]).
  • The DOM script imports ./img-util.js as a module; bundle it or ensure the base URL resolves correctly.
  • For source views or HTML previews, prefer applyImageTransformsToString() before mounting into the live DOM.

Example (bundler or app code that rerenders HTML):

import { runInPreview } from '@peaceroad/markdown-it-renderer-image/script/set-img-attributes.js'
import { defaultDomOptions } from '@peaceroad/markdown-it-renderer-image'

txt.addEventListener('input', async () => {
  const markdownCont = txt.value
  html.innerHTML = renderedHtml

  await runInPreview({
    root: html,
    markdownCont,
    ...defaultDomOptions,
    readMeta: true,
  })
})

Node vs DOM parity

To make Node and DOM results match (final src + width/height):

  • DOM: previewMode: 'output' and setDomSrc: true
  • Node: resolveSrc: true

Intentional differences:

  • DOM: previewMode can separate display src from final output URL (Node has no equivalent).
  • DOM: setDomSrc: false can skip DOM src rewriting while still sizing (Node has no equivalent).
  • Node: mdPath, disableRemoteSize, remoteTimeout control local/remote sizing (DOM has no equivalent).

Options (summary)

Node plugin options (defaults)

  • scaleSuffix (false): scale by @2x, 300dpi, 300ppi suffixes.
  • resize (false): resize by title hint.
  • autoHideResizeTitle (true): remove title when resize hint is used.
  • resizeDataAttr (data-img-resize): store resize hint when title is removed (set '' to disable).
  • lazyLoad (false): add loading="lazy".
  • asyncDecode (false): add decoding="async".
  • checkImgExtensions (png,jpg,jpeg,gif,webp): extensions to size.
  • resolveSrc (true): resolve final src using frontmatter (no-op without frontmatter or urlImageBase).
  • mdPath (empty): markdown file path or markdown directory for local sizing. When the path exists, Node uses fs.statSync to decide file vs directory. When the path does not exist, the heuristic is: trailing slash -> directory, otherwise treat paths with an extension as files and everything else as a directory. If you pass an extension-less file path that doesn't exist yet, it will be treated as a directory.
  • disableRemoteSize (false): skip remote sizing.
  • remoteTimeout (5000): sync fetch timeout in ms.
  • remoteMaxBytes (16MB): skip large remote images when content-length is present.
  • cacheMax (64): per-render cache size (0 disables cache).
  • suppressErrors (none): none | all | local | remote.
  • urlImageBase (empty): fallback base when frontmatter lacks urlimagebase.
  • outputUrlMode (absolute): absolute | protocol-relative | path-only.

DOM script options (defaults)

Same as Node options except remote sizing options, plus:

Scale/resize/title-handling and lazy/decoding options behave the same as the Node plugin: they affect width/height calculation and set loading/decoding attributes on the DOM.

  • readMeta (false): read meta[name="markdown-frontmatter"] (JSON).
  • previewMode (output): output | markdown | local.
    • output: display final URL (default).
    • markdown: display the original markdown src (best for drag & drop/blob mapping).
    • local: display a local file URL when lmd is an absolute path.
  • previewOutputSrcAttr (data-img-output-src): attribute name to store the final URL when previewMode !== output (set '' to disable).
  • loadSrcStrategy (output): pick the source for size probing. output | raw | display.
  • loadSrcStrategy: 'final' is accepted for backward compatibility and treated as output.
  • loadSrcPrefixMap (null): object map to rewrite loadSrc by prefix before probing (e.g., { "/img": "http://localhost:3000/img" }).
  • loadSrcResolver (null): function to override the measurement source (loadSrc) for size calculation (DOM only).
  • loadSrcMap (null): map of src -> loadSrc overrides for size calculation (DOM only).
  • setDomSrc (true): when false, leaves img.src untouched (size probing still runs).
  • enableSizeProbe (true): when false, skips size probing entirely (no network or image load).
  • awaitSizeProbes (true): wait for image load before resolving applyImageTransforms.
  • sizeProbeTimeoutMs (3000): timeout for size probes (0 disables).
  • onImageProcessed (null): per-image callback (imgEl, info) => {}.
  • suppressNoopWarning (false): silence the browser default-export warning.

readMeta is opt-in to avoid extra DOM work in normal pages; enable it for live preview scenarios (e.g., VS Code). When running a page from file://, the DOM script defaults suppressErrors to local and disables enableSizeProbe unless you explicitly override them, to reduce noisy console errors from local image probes. suppressErrors only silences renderer-image logs; browser network errors (CORS/404) can still appear in the console.

Editing/draft mode tip: to avoid noisy requests while users type, set setDomSrc: false, enableSizeProbe: false, and previewMode: 'markdown', then re-run transforms when the input stabilizes.

Options (details)

Resolve output image src from frontmatter or options

When resolveSrc: true (default), image src is resolved using frontmatter keys.

Frontmatter is used only when resolveSrc: true. If frontmatter (and urlImageBase) is missing, src is left untouched.

Frontmatter keys (lowercase only):

  • url: page base URL.
  • urlimage: image base URL (absolute) or image directory (relative/empty).
  • urlimagebase: base URL used with the path from url.
  • lid: local image directory prefix to strip from relative src so the remaining subpath can be reused in the final URL.
  • lmd: local media directory for DOM size loading. If it is an absolute path without a scheme, it is converted to a file:/// URL with encoded segments; relative paths are kept as-is.
  • imagescale: scale factor applied to all images (e.g. 60% or 0.6, values above 100% are capped).

Base selection order:

  1. urlimage when it is absolute (has a domain or starts with //).
  2. urlimagebase (frontmatter) or urlImageBase (option) + path from url.
  3. url.

If urlimage is relative (no domain), it becomes an image directory inserted between base and filename, and only the basename from src is used. Use urlimage: (empty) or urlimage: . to force basename-only without adding a directory.

Examples:

---
url: https://example.com/page
urlimage: images
---
![A cat.](cat.jpg)
# -> https://example.com/page/images/cat.jpg (relative urlimage uses basename-only)
---
urlimage: https://image.example.com/assets/
---
![A cat.](cat.jpg)
# -> https://image.example.com/assets/cat.jpg
---
url: https://example.com/page
urlimagebase: https://image.example.com/assets/
urlimage: images
---
![A cat.](cat.jpg)
# -> https://image.example.com/assets/page/images/cat.jpg

lid removes only the matching prefix and keeps the remaining subpath:

---
lid: image
---
![](image/cat.jpg)         # -> cat.jpg
![](image/chapter/cat.jpg) # -> chapter/cat.jpg

Example of a global scale factor:

---
imagescale: 60%
---
![](cat.jpg) # -> width/height scaled to 60%

imagescale is applied after scaleSuffix and only when no title resize hint is present (resize takes priority). Values above 100% are capped. Order:

  1. Read original size
  2. Apply scaleSuffix (e.g. @2x)
  3. Apply title resize (resize: true) if present
  4. Apply imagescale (global scale) only when step 3 is not used

Example: 400x300 image with @2x, title resize:50%, and imagescale: 0.5 -> 400x300 -> 200x150 -> 100x75 (imagescale skipped)

Local sizing in DOM (lmd)

In browsers, local file access is restricted. For local sizing in the DOM script, provide lmd (local markdown directory) as a path or a Webview URI:

---
lmd: C:\Users\User\Documents\manuscript
---

In VS Code, pass a Webview URI (e.g., asWebviewUri) instead of a raw file:// path.

Preview modes in DOM

When previewMode is markdown or local, the DOM script stores the final URL in previewOutputSrcAttr (default data-img-output-src) so you can copy/export HTML with the CDN URL. The original markdown src is cached in data-img-src-raw to keep reprocessing stable; lmd is still used for size measurement when available. In VS Code Webview, relative src may not resolve, so use previewMode: 'output' there.

If you need to measure sizes from Blob URLs (e.g., drag-and-drop files), pass loadSrcResolver or loadSrcMap so the DOM script uses those URLs only for measurement without changing the displayed src. Functions cannot be provided via readMeta JSON, so use direct options for loadSrcResolver. For JSON-only settings, use loadSrcStrategy (e.g. raw) and loadSrcPrefixMap to rewrite probing URLs without custom code.

Load source selection order for probing:

  1. Base source is picked by loadSrcStrategy (output, raw, or display).
  2. loadSrcPrefixMap (if set) rewrites the probe URL by prefix.
  3. loadSrcResolver (if provided) or loadSrcMap overrides everything.

raw uses the original markdown src and does not pass through lmd or urlImageBase. If raw is a relative path, size probes will likely fail unless you also provide lmd, loadSrcPrefixMap, or a resolver/map to convert it into a loadable URL.

JSON-only example (VS Code settings):

{
  "rendererImage.loadSrcStrategy": "raw",
  "rendererImage.loadSrcPrefixMap": {
    "/img/": "http://localhost:3000/img/"
  }
}

Only .html, .htm, .xhtml are treated as file names when deriving the path from url (used by urlimagebase).

  • url: https://example.com/page -> /page/
  • url: https://example.com/page/index.html -> /page/
  • url: https://example.com/v1.2/ -> /v1.2/

outputUrlMode

Applied at the end:

  • protocol-relative: https://a/b -> //a/b
  • path-only: https://a/b -> /b (same-origin only)

Modify output width/height attributes from filename suffixes

When scaleSuffix: true, scales dimensions by:

  • @2x (half size)
  • _300dpi / _300ppi (convert to 96dpi)

This is identified by imageFileName.match(/[@._-]([0-9]+)(x|dpi|ppi)$/)

Example:

const md = mdit().use(mditRendererImage, { scaleSuffix: true })
md.render('![A cat]([email protected])', { mdPath: mdFile })
// <img ... width="200" height="150"> //cat.jpg is 400px wide and 300px high.

Modify output width/height attributes from title resize hints

When resize: true, resizes dimensions by title patterns. Example:

const md = mdit().use(mditRendererImage, { resize: true })

md.render('![A cat](cat.jpg "Resize:50%")', { mdPath: mdPat })
// <img ... width="200" height="150"> //cat.jpg is 400px wide and 300px high.

Title patterns include:

  • Resize:50%
  • リサイズ:50%
  • サイズ変更:50%

This is identified by imgTitle.match(/(?:(?:(?:大きさ|サイズ)の?変更|リサイズ|resize(?:d to)?) *[::]? *([0-9]+)([%%]|px)|([0-9]+)([%%]|px)[にへ](?:(?:大きさ|サイズ)を?変更|リサイズ))/i)

For px values, the number is treated as the target width and height is scaled to preserve aspect ratio (e.g. 400x300 with resize:200px -> 200x150). The final size is capped at the original image dimensions (no upscaling).

When autoHideResizeTitle: true (default), titles with resize hints are removed (Node/DOM). Set autoHideResizeTitle: false to keep titles even when resize hints are used. Resize hints are preserved in resizeDataAttr by default (data-img-resize) using normalized values like 50% or 200px; set resizeDataAttr: '' to disable.

Default behavior example (when resize: true):

const md = mdit().use(mditRendererImage, { resize: true })

md.render('![Figure](cat.jpg "resize:50%")', { mdPath: mdPat })
// <img ... width="200" height="150" data-img-resize="50%">

If you render HTML with the Node plugin and then run the DOM script, keep resizeDataAttr: 'data-img-resize' (default) so the resize hint survives title removal. If you do not need DOM reprocessing, set resizeDataAttr: '' to avoid extra attributes.

Set loading and decoding attributes

  • lazyLoad: true -> loading="lazy"
  • asyncDecode: true -> decoding="async"

Check image extensions

Only files matching checkImgExtensions are sized. Query/hash is ignored.

Remote images (Node)

Remote sizing is synchronous. For extension hosts (e.g., VS Code), set disableRemoteSize: true and let the DOM script size remote images.

Testing

  • npm test (Node plugin + frontmatter tests)
  • npm run test:script (DOM script tests)

VS Code / Webview notes

  • Webview blocks file://. Pass lmd as a Webview URI (asWebviewUri) if you need local sizing in the DOM.
  • The DOM script imports ./img-util.js as a module; bundle it or ensure the base URL resolves correctly.

Note: Using with @peaceroad/markdown-it-figure-with-p-caption

markdown-it-figure-with-p-caption can auto-generate captions from title text when its detection rules match. To avoid conflicts, use title for one purpose only:

  • Title as resize hint (recommended): keep captions in a paragraph or alt text, and avoid caption-like strings in title. This lets autoHideResizeTitle work as intended.
  • Title as caption: do not put resize hints in title, or set autoHideResizeTitle: false so the title remains for caption detection.

In short: don’t mix resize hints and caption text in the same title.

Performance tips

  • Node: remote sizing is synchronous; set disableRemoteSize: true for extension hosts and rely on DOM sizing.
  • Node: keep cacheMax > 0 to avoid repeated I/O on the same image set.
  • DOM: for fast previews, set enableSizeProbe: false or awaitSizeProbes: false.
  • DOM: if you only need metadata, set setDomSrc: false to avoid triggering image loads.