├── .gitignore ├── .npmignore ├── README.md ├── index.mjs ├── package.json ├── rollup.config.mjs └── test ├── basic.js ├── decoding.js ├── dummy-200x200.png └── image-size.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | index.js 3 | package-lock.json 4 | 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test/ 3 | .gitignore 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 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(`![](example.png "image title")`); 20 | //

\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(`![](example.png "image title")`); 31 | //

\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(`![](example.png "image title")`); 42 | //

\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(`![](example.png "image title")`); 56 | //

\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 70 | -------------------------------------------------------------------------------- /index.mjs: -------------------------------------------------------------------------------- 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 | 7 | md.renderer.rules.image = function (tokens, idx, options, env, self) { 8 | var token = tokens[idx]; 9 | token.attrSet('loading', 'lazy'); 10 | 11 | if (mdOptions && mdOptions.decoding === true) { 12 | token.attrSet('decoding', 'async'); 13 | } 14 | 15 | if (mdOptions && mdOptions.base_path && mdOptions.image_size === true) { 16 | const imgSrc = token.attrGet('src'); 17 | const imgPath = path.join(mdOptions.base_path, imgSrc); 18 | const dimensions = imageSize(imgPath); 19 | 20 | token.attrSet('width', dimensions.width); 21 | token.attrSet('height', dimensions.height); 22 | } 23 | 24 | return defaultImageRenderer(tokens, idx, options, env, self); 25 | }; 26 | }; 27 | 28 | export default lazy_loading_plugin; 29 | 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markdown-it-image-lazy-loading", 3 | "version": "2.0.1", 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": "Ruan Yifeng ", 23 | "homepage": "https://github.com/ruanyf/markdown-it-image-lazy-loading", 24 | "repository": "https://github.com/ruanyf/markdown-it-image-lazy-loading.git", 25 | "license": "MIT", 26 | "dependencies": { 27 | "image-size": "^1.0.0" 28 | }, 29 | "devDependencies": { 30 | "markdown-it": "^14.0.0", 31 | "rollup": "^4.9.1", 32 | "tape": "^5.3.2" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | input: 'index.mjs', 3 | output: { 4 | file: 'index.js', 5 | format: 'cjs' 6 | }, 7 | external: ['image-size', 'node:path'] 8 | }; 9 | -------------------------------------------------------------------------------- /test/basic.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | 3 | var md = require('markdown-it')(); 4 | var lazy_loading = require('../index.js'); 5 | md.use(lazy_loading); 6 | 7 | test('lazy loading test', function (t) { 8 | t.plan(1); 9 | 10 | t.equal( 11 | md.render(`![](example.png "image title")`), 12 | '

\n' 13 | ); 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /test/decoding.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | 3 | var md = require('markdown-it')(); 4 | var lazy_loading = require('../index.js'); 5 | md.use(lazy_loading, { 6 | decoding: true, 7 | }); 8 | 9 | test('decoding test', function (t) { 10 | t.plan(1); 11 | 12 | t.equal( 13 | md.render(`![](example.png "image title")`), 14 | '

\n' 15 | ); 16 | 17 | }); 18 | 19 | -------------------------------------------------------------------------------- /test/dummy-200x200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruanyf/markdown-it-image-lazy-loading/4d4ce4ba27fe5ebed16cb72a719803a6382154d8/test/dummy-200x200.png -------------------------------------------------------------------------------- /test/image-size.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | 3 | var md = require('markdown-it')(); 4 | var lazy_loading = require('../index.js'); 5 | md.use(lazy_loading, { 6 | image_size: true, 7 | base_path: __dirname, 8 | }); 9 | 10 | test('image size test', function (t) { 11 | t.plan(1); 12 | 13 | t.equal( 14 | md.render(`![](dummy-200x200.png "image title")`), 15 | '

\n' 16 | ); 17 | 18 | }); 19 | 20 | --------------------------------------------------------------------------------