diff --git a/__tests__/e2e/.vitepress/config.ts b/__tests__/e2e/.vitepress/config.ts
index 84fc64f2..9c02cc26 100644
--- a/__tests__/e2e/.vitepress/config.ts
+++ b/__tests__/e2e/.vitepress/config.ts
@@ -86,6 +86,9 @@ const sidebar: DefaultTheme.Config['sidebar'] = {
export default defineConfig({
title: 'Example',
description: 'An example app using VitePress.',
+ markdown: {
+ lazyLoading: true
+ },
themeConfig: {
sidebar,
search: {
diff --git a/__tests__/e2e/markdown-extensions/index.md b/__tests__/e2e/markdown-extensions/index.md
index 36d6c028..47246c18 100644
--- a/__tests__/e2e/markdown-extensions/index.md
+++ b/__tests__/e2e/markdown-extensions/index.md
@@ -196,3 +196,7 @@ export default config
## Markdown File Inclusion with Range without End
+
+## Image Lazy Loading
+
+
\ No newline at end of file
diff --git a/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts b/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts
index 42a89891..23b8b1a0 100644
--- a/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts
+++ b/__tests__/e2e/markdown-extensions/markdown-extensions.test.ts
@@ -65,7 +65,7 @@ describe('Table of Contents', () => {
test('render toc', async () => {
const items = page.locator('#table-of-contents + nav ul li')
const count = await items.count()
- expect(count).toBe(35)
+ expect(count).toBe(36)
})
})
@@ -280,3 +280,10 @@ describe('Markdown File Inclusion', () => {
expect(await p.textContent()).not.toContain('title')
})
})
+
+describe('Image Lazy Loading', () => {
+ test('render loading="lazy" in the
tag', async () => {
+ const img = page.locator('#image-lazy-loading + p img')
+ expect(await img.getAttribute('loading')).toBe('lazy')
+ })
+})
diff --git a/docs/guide/markdown.md b/docs/guide/markdown.md
index c7fcbd47..132432b2 100644
--- a/docs/guide/markdown.md
+++ b/docs/guide/markdown.md
@@ -847,6 +847,19 @@ $$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$
| $\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}}$ |
| $\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?_ |
+## Image Lazy Loading
+
+You can enable lazy loading for each image tag in the content via config:
+
+```js
+// image lazy loading is disabled by default
+export default {
+ markdown: {
+ lazyLoading: true
+ }
+}
+```
+
## Advanced Configuration
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 --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts
index c549901d..e1fbf058 100644
--- a/src/node/markdown/markdown.ts
+++ b/src/node/markdown/markdown.ts
@@ -165,6 +165,11 @@ export interface MarkdownOptions extends MarkdownIt.Options {
* @see https://vitepress.dev/guide/markdown#math-equations
*/
math?: boolean | any
+ /**
+ * Support native lazy loading for the
tag.
+ * @default false
+ */
+ lazyLoading?: boolean
}
export type MarkdownRenderer = MarkdownIt
@@ -197,7 +202,7 @@ export const createMarkdownRenderer = async (
.use(preWrapperPlugin, { hasSingleTheme })
.use(snippetPlugin, srcDir)
.use(containerPlugin, { hasSingleTheme }, options.container)
- .use(imagePlugin)
+ .use(imagePlugin, options?.lazyLoading)
.use(
linkPlugin,
{ target: '_blank', rel: 'noreferrer', ...options.externalLinks },
diff --git a/src/node/markdown/plugins/image.ts b/src/node/markdown/plugins/image.ts
index 06d1a360..7fcd8bcd 100644
--- a/src/node/markdown/plugins/image.ts
+++ b/src/node/markdown/plugins/image.ts
@@ -3,7 +3,7 @@
import type MarkdownIt from 'markdown-it'
import { EXTERNAL_URL_RE } from '../../shared'
-export const imagePlugin = (md: MarkdownIt) => {
+export const imagePlugin = (md: MarkdownIt, lazyLoading: boolean) => {
const imageRule = md.renderer.rules.image!
md.renderer.rules.image = (tokens, idx, options, env, self) => {
const token = tokens[idx]
@@ -12,6 +12,9 @@ export const imagePlugin = (md: MarkdownIt) => {
if (!/^\.?\//.test(url)) url = './' + url
token.attrSet('src', decodeURIComponent(url))
}
+ if (lazyLoading) {
+ token.attrSet('loading', 'lazy')
+ }
return imageRule(tokens, idx, options, env, self)
}
}