@parksb/markdown-it-image-lazy-loading 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -0
- package/index.js +50 -0
- package/index.mjs +48 -0
- package/package.json +37 -0
- package/rollup.config.mjs +8 -0
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
A markdown-it plugin supporting Chrome 75's [native image lazy-loading](https://addyosmani.com/blog/lazy-loading/) and [async decoding](https://github.com/whatwg/html/pull/3221).
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
$ npm install markdown-it-image-lazy-loading
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
Load it in ES module.
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import markdownit from 'markdown-it';
|
|
15
|
+
import lazy_loading from 'markdown-it-image-lazy-loading';
|
|
16
|
+
|
|
17
|
+
const md = markdownit();
|
|
18
|
+
md.use(lazy_loading);
|
|
19
|
+
md.render(``);
|
|
20
|
+
// <p><img src="example.png" alt="" title="image title" loading="lazy"></p>\n
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or load it in CommonJS module.
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
const md = require('markdown-it')();
|
|
27
|
+
const lazy_loading = require('markdown-it-image-lazy-loading');
|
|
28
|
+
md.use(lazy_loading);
|
|
29
|
+
|
|
30
|
+
md.render(``);
|
|
31
|
+
// <p><img src="example.png" alt="" title="image title" loading="lazy"></p>\n
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If you want the `decoding="async"` attribute, enable the plugin's `decoding` option.
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
md.use(lazy_loading, {
|
|
38
|
+
decoding: true,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
md.render(``);
|
|
42
|
+
// <p><img src="example.png" alt="" title="image title" loading="lazy" decoding="async"></p>\n
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The plugin can also add `width` and `height` attributes to each image. This can prevent [cumulative layout shifts (CLS)](https://web.dev/cls/):
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
md.use(lazy_loading, {
|
|
49
|
+
image_size: true,
|
|
50
|
+
|
|
51
|
+
// Where your images are stored
|
|
52
|
+
base_path: __dirname + 'src/',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
md.render(``);
|
|
56
|
+
// <p><img src="example.png" alt="" title="image title" loading="lazy" width="100" height="100"></p>\n
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
To keep images responsive, also include the following CSS:
|
|
60
|
+
```css
|
|
61
|
+
img{
|
|
62
|
+
max-width: 100%;
|
|
63
|
+
height: auto;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var imageSize = require('image-size');
|
|
4
|
+
var path = require('node:path');
|
|
5
|
+
|
|
6
|
+
function lazy_loading_plugin(md, mdOptions) {
|
|
7
|
+
var defaultImageRenderer = md.renderer.rules.image;
|
|
8
|
+
var count = 0;
|
|
9
|
+
|
|
10
|
+
var skipCount = mdOptions && mdOptions.skip_count !== undefined ? mdOptions.skip_count : 0;
|
|
11
|
+
var excludeExtensions = mdOptions && mdOptions.exclude_extensions || [];
|
|
12
|
+
var maxWidth = mdOptions && mdOptions.max_width !== undefined ? mdOptions.max_width : null;
|
|
13
|
+
|
|
14
|
+
md.renderer.rules.image = function (tokens, idx, options, env, self) {
|
|
15
|
+
var token = tokens[idx];
|
|
16
|
+
if (count >= skipCount) {
|
|
17
|
+
token.attrSet('loading', 'lazy');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (mdOptions && mdOptions.decoding === true) {
|
|
21
|
+
token.attrSet('decoding', 'async');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (mdOptions && mdOptions.base_path && mdOptions.image_size === true) {
|
|
25
|
+
const imgSrc = token.attrGet('src');
|
|
26
|
+
|
|
27
|
+
const imgExt = path.extname(imgSrc);
|
|
28
|
+
if (excludeExtensions.includes(imgExt)) {
|
|
29
|
+
return defaultImageRenderer(tokens, idx, options, env, self);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const imgPath = path.join(mdOptions.base_path, imgSrc);
|
|
33
|
+
const dimensions = imageSize(imgPath);
|
|
34
|
+
|
|
35
|
+
if (maxWidth !== null && dimensions.width > maxWidth) {
|
|
36
|
+
dimensions.height = Math.round(dimensions.height * (maxWidth / dimensions.width));
|
|
37
|
+
dimensions.width = maxWidth;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
token.attrSet('width', dimensions.width);
|
|
41
|
+
token.attrSet('height', dimensions.height);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
count += 1;
|
|
45
|
+
|
|
46
|
+
return defaultImageRenderer(tokens, idx, options, env, self);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = lazy_loading_plugin;
|
package/index.mjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import imageSize from 'image-size';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
function lazy_loading_plugin(md, mdOptions) {
|
|
5
|
+
var defaultImageRenderer = md.renderer.rules.image;
|
|
6
|
+
var count = 0;
|
|
7
|
+
|
|
8
|
+
var skipCount = mdOptions && mdOptions.skip_count !== undefined ? mdOptions.skip_count : 0;
|
|
9
|
+
var excludeExtensions = mdOptions && mdOptions.exclude_extensions || [];
|
|
10
|
+
var maxWidth = mdOptions && mdOptions.max_width !== undefined ? mdOptions.max_width : null;
|
|
11
|
+
|
|
12
|
+
md.renderer.rules.image = function (tokens, idx, options, env, self) {
|
|
13
|
+
var token = tokens[idx];
|
|
14
|
+
if (count >= skipCount) {
|
|
15
|
+
token.attrSet('loading', 'lazy');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (mdOptions && mdOptions.decoding === true) {
|
|
19
|
+
token.attrSet('decoding', 'async');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (mdOptions && mdOptions.base_path && mdOptions.image_size === true) {
|
|
23
|
+
const imgSrc = token.attrGet('src');
|
|
24
|
+
|
|
25
|
+
const imgExt = path.extname(imgSrc);
|
|
26
|
+
if (excludeExtensions.includes(imgExt)) {
|
|
27
|
+
return defaultImageRenderer(tokens, idx, options, env, self);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const imgPath = path.join(mdOptions.base_path, imgSrc);
|
|
31
|
+
const dimensions = imageSize(imgPath);
|
|
32
|
+
|
|
33
|
+
if (maxWidth !== null && dimensions.width > maxWidth) {
|
|
34
|
+
dimensions.height = Math.round(dimensions.height * (maxWidth / dimensions.width));
|
|
35
|
+
dimensions.width = maxWidth;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
token.attrSet('width', dimensions.width);
|
|
39
|
+
token.attrSet('height', dimensions.height);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
count += 1;
|
|
43
|
+
|
|
44
|
+
return defaultImageRenderer(tokens, idx, options, env, self);
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default lazy_loading_plugin;
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@parksb/markdown-it-image-lazy-loading",
|
|
3
|
+
"version": "2.0.2",
|
|
4
|
+
"description": "a markdown-it plugin supporting Chrome 75's native image lazy-loading",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./index.mjs",
|
|
9
|
+
"require": "./index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "rollup --config rollup.config.mjs",
|
|
14
|
+
"test": "npm run build && npx tape test/*.js",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"markdown-it-plugin",
|
|
19
|
+
"markdown-it",
|
|
20
|
+
"lazyload"
|
|
21
|
+
],
|
|
22
|
+
"author": "parksb <parkgds@gmail.com>",
|
|
23
|
+
"homepage": "https://github.com/parksb/markdown-it-image-lazy-loading",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/parksb/markdown-it-image-lazy-loading.git"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"image-size": "^1.0.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"markdown-it": "^14.0.0",
|
|
34
|
+
"rollup": "^4.9.1",
|
|
35
|
+
"tape": "^5.3.2"
|
|
36
|
+
}
|
|
37
|
+
}
|