Skip to content

Commit 55be3f1

Browse files
zonemeenbrc-dd
andauthored
feat: support custom image lazy loading (#3346)
Co-authored-by: Divyansh Singh <[email protected]>
1 parent 203446d commit 55be3f1

File tree

6 files changed

+47
-4
lines changed

6 files changed

+47
-4
lines changed

Diff for: __tests__/e2e/.vitepress/config.ts

+5
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ const sidebar: DefaultTheme.Config['sidebar'] = {
8686
export default defineConfig({
8787
title: 'Example',
8888
description: 'An example app using VitePress.',
89+
markdown: {
90+
image: {
91+
lazyLoading: true
92+
}
93+
},
8994
themeConfig: {
9095
sidebar,
9196
search: {

Diff for: __tests__/e2e/markdown-extensions/index.md

+4
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,7 @@ export default config
196196
## Markdown File Inclusion with Range without End
197197

198198
<!--@include: ./foo.md{6,}-->
199+
200+
## Image Lazy Loading
201+
202+
![vitepress logo](/vitepress.png)

Diff for: __tests__/e2e/markdown-extensions/markdown-extensions.test.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ describe('Table of Contents', () => {
6565
test('render toc', async () => {
6666
const items = page.locator('#table-of-contents + nav ul li')
6767
const count = await items.count()
68-
expect(count).toBe(35)
68+
expect(count).toBe(36)
6969
})
7070
})
7171

@@ -280,3 +280,10 @@ describe('Markdown File Inclusion', () => {
280280
expect(await p.textContent()).not.toContain('title')
281281
})
282282
})
283+
284+
describe('Image Lazy Loading', () => {
285+
test('render loading="lazy" in the <img> tag', async () => {
286+
const img = page.locator('#image-lazy-loading + p img')
287+
expect(await img.getAttribute('loading')).toBe('lazy')
288+
})
289+
})

Diff for: docs/guide/markdown.md

+15
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,21 @@ $$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
847847
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl of $\vec{\mathbf{E}}$ is proportional to the rate of change of $\vec{\mathbf{B}}$ |
848848
| $\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _wha?_ |
849849

850+
## Image Lazy Loading
851+
852+
You can enable lazy loading for each image added via markdown by setting `lazyLoading` to `true` in your config file:
853+
854+
```js
855+
export default {
856+
markdown: {
857+
image: {
858+
// image lazy loading is disabled by default
859+
lazyLoading: true
860+
}
861+
}
862+
}
863+
```
864+
850865
## Advanced Configuration
851866

852867
VitePress uses [markdown-it](https://github.com/markdown-it/markdown-it) as the Markdown renderer. A lot of the extensions above are implemented via custom plugins. You can further customize the `markdown-it` instance using the `markdown` option in `.vitepress/config.js`:

Diff for: src/node/markdown/markdown.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import type { Logger } from 'vite'
2323
import { containerPlugin, type ContainerOptions } from './plugins/containers'
2424
import { highlight } from './plugins/highlight'
2525
import { highlightLinePlugin } from './plugins/highlightLines'
26-
import { imagePlugin } from './plugins/image'
26+
import { imagePlugin, type Options as ImageOptions } from './plugins/image'
2727
import { lineNumberPlugin } from './plugins/lineNumbers'
2828
import { linkPlugin } from './plugins/link'
2929
import { preWrapperPlugin } from './plugins/preWrapper'
@@ -166,6 +166,7 @@ export interface MarkdownOptions extends MarkdownIt.Options {
166166
* @see https://vitepress.dev/guide/markdown#math-equations
167167
*/
168168
math?: boolean | any
169+
image?: ImageOptions
169170
}
170171

171172
export type MarkdownRenderer = MarkdownIt
@@ -198,7 +199,7 @@ export const createMarkdownRenderer = async (
198199
.use(preWrapperPlugin, { hasSingleTheme })
199200
.use(snippetPlugin, srcDir)
200201
.use(containerPlugin, { hasSingleTheme }, options.container)
201-
.use(imagePlugin)
202+
.use(imagePlugin, options.image)
202203
.use(
203204
linkPlugin,
204205
{ target: '_blank', rel: 'noreferrer', ...options.externalLinks },

Diff for: src/node/markdown/plugins/image.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@
33
import type MarkdownIt from 'markdown-it'
44
import { EXTERNAL_URL_RE } from '../../shared'
55

6-
export const imagePlugin = (md: MarkdownIt) => {
6+
export interface Options {
7+
/**
8+
* Support native lazy loading for the `<img>` tag.
9+
* @default false
10+
*/
11+
lazyLoading?: boolean
12+
}
13+
14+
export const imagePlugin = (md: MarkdownIt, { lazyLoading }: Options = {}) => {
715
const imageRule = md.renderer.rules.image!
816
md.renderer.rules.image = (tokens, idx, options, env, self) => {
917
const token = tokens[idx]
@@ -12,6 +20,9 @@ export const imagePlugin = (md: MarkdownIt) => {
1220
if (!/^\.?\//.test(url)) url = './' + url
1321
token.attrSet('src', decodeURIComponent(url))
1422
}
23+
if (lazyLoading) {
24+
token.attrSet('loading', 'lazy')
25+
}
1526
return imageRule(tokens, idx, options, env, self)
1627
}
1728
}

0 commit comments

Comments
 (0)