Travis

Travis

这里支持的小组件太少,写不下😂,欢迎查看我的个人 blog <blog.lxythan2lxy.cn>

Add a blurred placeholder for images in Next.js.

This article's permanent link is Adding Blurred Image Placeholder in Next.js | Travis' Blog

The content of this article is from How to: Blurred images on load in Next.js, and the modified code is in my this commit.

Introduction#

Next.js's Image component supports the blurDataURL parameter, which can use a base64 image as a placeholder before the image is fully loaded.

In order to control the image position using markdown syntax in mdx and generate the blurred image during server build instead of generating it after getting the image on the frontend, we cannot write the generation process in the image component. Instead, it should be done when mdx is rendered into tsx objects. To control this process, I used the rehype plugin1.

My mdx file is managed by contentlayer. It is first converted from mdx to html using remark, then processed using rehype, and finally converted to tsx for rendering. This series of processes is completed during the next build phase, which happens to meet the requirements.

Getting Started#

  1. First, install the required packages. plaiceholder is a package that can generate corresponding blurred placeholder images using images and directly generate base64 format.
pnpm i plaiceholder unist-util-visit
  1. Next, find the corresponding img tag, read the corresponding src file, generate the corresponding base64 string using plaiceholder, and put it into the blurDataURL attribute of the img. Then, use our own Component to handle the parameters.
import { getPlaiceholder } from "plaiceholder";
import { visit } from "unist-util-visit";

// Just to check if the node is an image node
function isImageNode(node) {
  const img = node;
  return (
    img.type === "element" &&
    img.tagName === "img" &&
    img.properties &&
    typeof img.properties.src === "string"
  );
}

// Returns the props of given `src` to use for blurred images
export async function returnProps(src) {
  const { base64: blurDataURL, img } = await getPlaiceholder(src);

  // If an error happened calculating the resolution, throw an error
  if (!img) throw Error(`Invalid image with src "${src}"`);

  return {
    blurDataURL,
  };
}

async function addProps(node) {
  // return the new props we'll need for our image
  const { blurDataURL } = await returnProps(node.properties.src);

  node.properties.blurDataURL = blurDataURL;
}

const imageMetadata = () => {
  return async function transformer(tree) {
    // Create an array to hold all of the images from the markdown file
    const images = [];

    visit(tree, "element", (node) => {
      // Visit every node in the tree, check if it's an image and push it in the images array
      if (isImageNode(node)) {
        images.push(node);
      }
    });

    for (const image of images) {
      // Loop through all of the images and add their props
      await addProps(image);
    }

    return tree;
  };
};

export default imageMetadata;
  1. Convert the img tag to Next.js's Image.
import Image from "next/image";

export default function MyImage({
  src,
  width,
  height,
  alt,
  blurDataURL,
}: any) {
  return (
    <div className="not-prose mx-2 mt-4 mb-0 break-inside-avoid-page">
      <div>
        <Image
          src={`${src}`}
          width={width}
          height={height}
          alt={alt}
          blurDataURL={blurDataURL}
          placeholder="blur"
        />
      </div>
    </div>
  );
}
  1. Add the rehype plugin to the contentlayer settings.
import imageMetadata from "./lib/imageMetadata";

...

export default makeSource({
  contentDirPath: "data",
  documentTypes: [Blog, Movie, About, Idea],
  mdx: {
    rehypePlugins: [
      [rehypeImgSize, { dir: "public" }],
      rehypeCodeTitles,
      imageMetadata,
      [rehypePrism, { showLineNumbers: true }],
      rehypeKatex,
      rehypeSlug,
    ],
  },
});

OK, that's it.

Footnotes#

  1. Github rehypejs/rehype

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.