feat: support custom image lazy loading (#3346)

Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
pull/2866/merge
烽宁 9 months ago committed by GitHub
parent 203446d691
commit 55be3f14d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -86,6 +86,11 @@ const sidebar: DefaultTheme.Config['sidebar'] = {
export default defineConfig({ export default defineConfig({
title: 'Example', title: 'Example',
description: 'An example app using VitePress.', description: 'An example app using VitePress.',
markdown: {
image: {
lazyLoading: true
}
},
themeConfig: { themeConfig: {
sidebar, sidebar,
search: { search: {

@ -196,3 +196,7 @@ export default config
## Markdown File Inclusion with Range without End ## Markdown File Inclusion with Range without End
<!--@include: ./foo.md{6,}--> <!--@include: ./foo.md{6,}-->
## Image Lazy Loading
![vitepress logo](/vitepress.png)

@ -65,7 +65,7 @@ describe('Table of Contents', () => {
test('render toc', async () => { test('render toc', async () => {
const items = page.locator('#table-of-contents + nav ul li') const items = page.locator('#table-of-contents + nav ul li')
const count = await items.count() 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') expect(await p.textContent()).not.toContain('title')
}) })
}) })
describe('Image Lazy Loading', () => {
test('render loading="lazy" in the <img> tag', async () => {
const img = page.locator('#image-lazy-loading + p img')
expect(await img.getAttribute('loading')).toBe('lazy')
})
})

@ -847,6 +847,21 @@ $$ 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{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?_ | | $\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 added via markdown by setting `lazyLoading` to `true` in your config file:
```js
export default {
markdown: {
image: {
// image lazy loading is disabled by default
lazyLoading: true
}
}
}
```
## Advanced Configuration ## 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`: 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`:

@ -23,7 +23,7 @@ import type { Logger } from 'vite'
import { containerPlugin, type ContainerOptions } from './plugins/containers' import { containerPlugin, type ContainerOptions } from './plugins/containers'
import { highlight } from './plugins/highlight' import { highlight } from './plugins/highlight'
import { highlightLinePlugin } from './plugins/highlightLines' import { highlightLinePlugin } from './plugins/highlightLines'
import { imagePlugin } from './plugins/image' import { imagePlugin, type Options as ImageOptions } from './plugins/image'
import { lineNumberPlugin } from './plugins/lineNumbers' import { lineNumberPlugin } from './plugins/lineNumbers'
import { linkPlugin } from './plugins/link' import { linkPlugin } from './plugins/link'
import { preWrapperPlugin } from './plugins/preWrapper' import { preWrapperPlugin } from './plugins/preWrapper'
@ -166,6 +166,7 @@ export interface MarkdownOptions extends MarkdownIt.Options {
* @see https://vitepress.dev/guide/markdown#math-equations * @see https://vitepress.dev/guide/markdown#math-equations
*/ */
math?: boolean | any math?: boolean | any
image?: ImageOptions
} }
export type MarkdownRenderer = MarkdownIt export type MarkdownRenderer = MarkdownIt
@ -198,7 +199,7 @@ export const createMarkdownRenderer = async (
.use(preWrapperPlugin, { hasSingleTheme }) .use(preWrapperPlugin, { hasSingleTheme })
.use(snippetPlugin, srcDir) .use(snippetPlugin, srcDir)
.use(containerPlugin, { hasSingleTheme }, options.container) .use(containerPlugin, { hasSingleTheme }, options.container)
.use(imagePlugin) .use(imagePlugin, options.image)
.use( .use(
linkPlugin, linkPlugin,
{ target: '_blank', rel: 'noreferrer', ...options.externalLinks }, { target: '_blank', rel: 'noreferrer', ...options.externalLinks },

@ -3,7 +3,15 @@
import type MarkdownIt from 'markdown-it' import type MarkdownIt from 'markdown-it'
import { EXTERNAL_URL_RE } from '../../shared' import { EXTERNAL_URL_RE } from '../../shared'
export const imagePlugin = (md: MarkdownIt) => { export interface Options {
/**
* Support native lazy loading for the `<img>` tag.
* @default false
*/
lazyLoading?: boolean
}
export const imagePlugin = (md: MarkdownIt, { lazyLoading }: Options = {}) => {
const imageRule = md.renderer.rules.image! const imageRule = md.renderer.rules.image!
md.renderer.rules.image = (tokens, idx, options, env, self) => { md.renderer.rules.image = (tokens, idx, options, env, self) => {
const token = tokens[idx] const token = tokens[idx]
@ -12,6 +20,9 @@ export const imagePlugin = (md: MarkdownIt) => {
if (!/^\.?\//.test(url)) url = './' + url if (!/^\.?\//.test(url)) url = './' + url
token.attrSet('src', decodeURIComponent(url)) token.attrSet('src', decodeURIComponent(url))
} }
if (lazyLoading) {
token.attrSet('loading', 'lazy')
}
return imageRule(tokens, idx, options, env, self) return imageRule(tokens, idx, options, env, self)
} }
} }

Loading…
Cancel
Save