There is an audit item named Image elements have explicit width and height
in Lighthouse.
Its detail is described in Images without dimensions, which says that setting width
and height
attributes to <img>
tag improves CLS (Cumulative Layout Shift).
However, in nuxt/content, it seemed that they are not set automatically when the images are specified with ![](URL)
notation. So I created a rehype plugin named rehype-img-size and let it set image size attributes automatically by reading files.
We can access local file system if we build pages with SSG as prerequisites, so it's possible to read image file size from src
attribute of <img>
tag and set width
and height
attributes by manipulating HTML which is converted from Markdown with rehype
.
In addition, if you write CSS like below, even the large files won't overflow, so you can easily handle this issue without checking size of every files or rewriting them as <img width="..>"
.
p img {
max-width: 100%;
height: 100%;
}
First, you must install the plugin as described in the README of rehype-img-size plugin.
npm install rehype-img-size
For example, there is a Markdown file
![](img.png)
and example.js
as follows:
const unified = require('unified')
const parse = require('remark-parse')
const remark2rehype = require('remark-rehype')
const stringify = require('rehype-stringify')
const vfile = require('to-vfile')
const rehypeImgSize = require('rehype-img-size')
unified()
.use(parse)
.use(remark2rehype)
.use(rehypeImgSize)
.use(stringify)
.process(vfile.readSync('index.md'), function(err, file) {
if (err) throw err
console.log(file.contents)
})
If you run node example
, then width
and height
attributes will be added to the <img>
tag.
<p><img src="img.png" alt="" width="640" height="480"></p>
This is the usage as a rehype plugin. When you use it with nuxt/content, you just have to add a config to content.markdown.rehypePlugin
in nuxt.config.js
.
export default {
content: {
markdown: {
rehypePlugins: [
[ 'rehype-img-size', { dir: 'static' } ]
]
}
}
}
On nuxt/content, static
directory is the location for static files by default, so if the published image paths are written in Markdown files in content
directory which the Markdown files are located, the plugin cannot open the files because the plugin doesn't know static
directory.
That's why the configuration above has the option dir
to specify the location of static files.
With this configuration, an image file specified by ![](/image.png)
in Markdown can be recognized as ./static/image.png
by the plugin.
Maybe it is easy for you to imagine that remark or rehype can be used because it's explained in the very beginning of the nuxt/content document such as Writing content.
I tried to find an appropriate plugin from the list of rehype plugin, but couldn't find it. rehype-resolution seemed to be very close to what I was looking for, but this is a tool to set srcset
attribute and didn't match to my requirement.
There is a Create plugin
section in the bottom of this page, and the linked article Creating a plugin with unified might help you understand how to create a plugin. I thought I must learn lots of API first, but it was not true. Basically all I have to do is to receive the AST and write what I want to do with it. This AST is an HTML syntax tree called hast, and by using unist-util-visit
for unist that is more abstract concept than hast, you can start writing some process against a node with less code.
const visit = require('unist-util-visit')
module.exports = attacher
function attacher(options) {
function transformer(tree, file) {
visit(tree, 'element', visitor)
function visitor(node) {
// some process with node
}
}
}