Color mode

Responsive Image

Upgrades existing <img> elements with lazy loading and responsive <picture> / srcset markup, using only image variants that are already present in the content manifest.

日本語

Overview

responsiveImage() runs as a build-time HTML layer:

  1. It always adds loading="lazy" and decoding="async" to <img> elements unless those attributes are already set.
  2. It adds a sizes attribute when one is missing.
  3. It looks for sibling variants that already exist in the manifest (photo.webp, photo.avif, photo-640.webp, photo-640.png, …). When variants are found the <img> becomes a <picture> element with grouped <source> elements. When no variants are found the <img> is left in place with just the added attributes.

The plugin never fabricates URLs and never writes files. It only references assets that the manifest already knows about.

Usage

ts
import { defineConfig } from "@riebeckite/core";
import { attachment } from "@riebeckite/plugin-attachment";
import { obsidianMarkdown } from "@riebeckite/plugin-obsidian-markdown";
import { responsiveImage } from "@riebeckite/plugin-responsive-image";
 
export default defineConfig({
  // ...
  plugins: [obsidianMarkdown(), attachment(), responsiveImage()],
});

responsiveImage() uses order: 100, so it runs after the media and attachment renderers.

Options

Option Type Default Description
lazy boolean true Adds loading="lazy" when absent
decoding boolean true Adds decoding="async" when absent
sizes string "100vw" Fallback sizes value added when absent
widths number[] [640, 1280, 1920] Width variants to look up
formats string[] ["webp", "avif"] Format variants to look up
className string "rb-responsive-image" Class applied to <picture>
generate boolean false Reserved
outputDir string unset Reserved

Variant discovery

Variants are matched against the asset paths the manifest already contains:

  • format variants: photo.webp, photo.avif
  • width variants: photo-640.webp, photo-1280.avif, photo-1920.png
  • width variants in the original format: photo-640.png

The plugin maps the original <img src> back to a manifest asset by trying the site asset URL (/attachments/photo.png) and the attachment URL (/assets/attachments/photo.png). If the source cannot be matched to a manifest asset, the <img> is left untouched.

Limitation: no image encoding

This plugin is a deterministic discovery/HTML layer. It does not encode or generate new image files by default. PluginAsset only supports style and script module specifiers, so Core currently exposes no supported way for a plugin to emit arbitrary binary files into the build output.

generate and outputDir are reserved for a future release and do nothing today. Adding real encoding requires a Core file-emission API; until then, pre-generate the variants yourself (for example with an external image tool) and commit them next to the original image. Sites copy referenced vault assets into public/ through apps/web/scripts/build_images.ts.

Exports

  • responsiveImage(options?) / responsiveImagePlugin — plugin factory
  • resolveResponsiveImageOptions(options?) — resolve defaults
  • buildResponsiveSrcset(existingPaths, src, options?) — pure srcset planner
  • applyResponsiveImages(html, existingPaths, options?) — HTML transform
  • collectKnownAssetPaths(manifest) — manifest asset set helper
  • Types: ResponsiveImageOptions, ResolvedResponsiveImageOptions, ResponsiveImagePlan, ResponsiveImageSource, ResponsiveImageVariant

See also

History

1 changesCollapseExpand
1 + <!-- Generated from packages/plugins/responsive-image/README.md. Do not edit this page directly; edit the package README and run `pnpm docs:sync`. -->
2 +
3 + # Responsive Image
4 +
5 + Upgrades existing `<img>` elements with lazy loading and responsive
6 + `<picture>` / `srcset` markup, using only image variants that are already
7 + present in the content manifest.
8 +
9 + [日本語](./responsive-image.md)
10 +
11 + ## Overview
12 +
13 + `responsiveImage()` runs as a build-time HTML layer:
14 +
15 + 1. It always adds `loading="lazy"` and `decoding="async"` to `<img>` elements
16 + unless those attributes are already set.
17 + 2. It adds a `sizes` attribute when one is missing.
18 + 3. It looks for sibling variants that already exist in the manifest
19 + (`photo.webp`, `photo.avif`, `photo-640.webp`, `photo-640.png`, …). When
20 + variants are found the `<img>` becomes a `<picture>` element with grouped
21 + `<source>` elements. When no variants are found the `<img>` is left in place
22 + with just the added attributes.
23 +
24 + The plugin never fabricates URLs and never writes files. It only references
25 + assets that the manifest already knows about.
26 +
27 + ## Usage
28 +
29 + ```ts
30 + import { defineConfig } from "@riebeckite/core";
31 + import { attachment } from "@riebeckite/plugin-attachment";
32 + import { obsidianMarkdown } from "@riebeckite/plugin-obsidian-markdown";
33 + import { responsiveImage } from "@riebeckite/plugin-responsive-image";
34 +
35 + export default defineConfig({
36 + // ...
37 + plugins: [obsidianMarkdown(), attachment(), responsiveImage()],
38 + });
39 + ```
40 +
41 + `responsiveImage()` uses `order: 100`, so it runs after the media and
42 + attachment renderers.
43 +
44 + ## Options
45 +
46 + | Option | Type | Default | Description |
47 + | ------ | ---- | ------- | ----------- |
48 + | `lazy` | `boolean` | `true` | Adds `loading="lazy"` when absent |
49 + | `decoding` | `boolean` | `true` | Adds `decoding="async"` when absent |
50 + | `sizes` | `string` | `"100vw"` | Fallback `sizes` value added when absent |
51 + | `widths` | `number[]` | `[640, 1280, 1920]` | Width variants to look up |
52 + | `formats` | `string[]` | `["webp", "avif"]` | Format variants to look up |
53 + | `className` | `string` | `"rb-responsive-image"` | Class applied to `<picture>` |
54 + | `generate` | `boolean` | `false` | Reserved |
55 + | `outputDir` | `string` | unset | Reserved |
56 +
57 + ## Variant discovery
58 +
59 + Variants are matched against the asset paths the manifest already contains:
60 +
61 + - format variants: `photo.webp`, `photo.avif`
62 + - width variants: `photo-640.webp`, `photo-1280.avif`, `photo-1920.png`
63 + - width variants in the original format: `photo-640.png`
64 +
65 + The plugin maps the original `<img src>` back to a manifest asset by trying the
66 + site asset URL (`/attachments/photo.png`) and the attachment URL
67 + (`/assets/attachments/photo.png`). If the source cannot be matched to a manifest
68 + asset, the `<img>` is left untouched.
69 +
70 + ## Limitation: no image encoding
71 +
72 + This plugin is a deterministic discovery/HTML layer. It does **not** encode or
73 + generate new image files by default. `PluginAsset` only supports `style` and
74 + `script` module specifiers, so Core currently exposes no supported way for a
75 + plugin to emit arbitrary binary files into the build output.
76 +
77 + `generate` and `outputDir` are reserved for a future release and do nothing
78 + today. Adding real encoding requires a Core file-emission API; until then,
79 + pre-generate the variants yourself (for example with an external image tool) and
80 + commit them next to the original image. Sites copy referenced vault assets into
81 + `public/` through `apps/web/scripts/build_images.ts`.
82 +
83 + ## Exports
84 +
85 + - `responsiveImage(options?)` / `responsiveImagePlugin` — plugin factory
86 + - `resolveResponsiveImageOptions(options?)` — resolve defaults
87 + - `buildResponsiveSrcset(existingPaths, src, options?)` — pure srcset planner
88 + - `applyResponsiveImages(html, existingPaths, options?)` — HTML transform
89 + - `collectKnownAssetPaths(manifest)` — manifest asset set helper
90 + - Types: `ResponsiveImageOptions`, `ResolvedResponsiveImageOptions`,
91 + `ResponsiveImagePlan`, `ResponsiveImageSource`, `ResponsiveImageVariant`
92 +
93 + ## See also
94 +
95 + - [Plugin guide](../reference/plugin-api.en.md)
96 +