Next.js でリモート画像用の blurDataURL を生成する
Originally posted at: nikolovlazar.com/blog/generating-blur-for-dynamic-images-nextjs
Next.js Image Component は IMO であり、画像を確実にするために使用できる最高のツールです.
Next.js Web サイトの最適化が行われ、ページの読み込みが速くなります.
next/image
コンポーネントの興味深い機能の 1 つprovides は
placeholder
prop で、その値は blur
または empty
のいずれかです.プレースホルダーが
blur
に設定されている場合、 blurDataURL
を提供する必要があります.ローカル画像を静的にインポートする場合、Next.jsリソースにアクセスして、
blurDataURL
を生成できます.しかし、そこにあるリモート画像にぼかし効果を追加したい場合私たちがしなければならないことがいくつかあります:
next.config.js
blurDataURL
and pass it to the NextImage
component 私は自分のウェブサイトのコンテンツ (これ!) に MDX を使用しているので、この記事では
blurDataURL
について説明します.世代は MDX と統合されていますが、機能は一般的であり、MDX とはまったく関係がありません.それでは始めましょう!
プロバイダー ドメインの登録
まず、リモート イメージを
next/image
でレンダリングするには、プロバイダーのドメインを登録する必要があります.私の場合、GitHub から
og:image
を読み込んでいます.URL は次のようになります.https://opengraph.githubassets.com/f4a95bd3aa5113a1f599f5a810edeb16b885f3364b0443dc3c34a02c3290a5d8/chakra-ui/chakra-ui-docs/pull/154
URL を見ると、
opengraph.githubassets.com
ドメインを登録する必要があることがわかります.next.config.js
にジャンプしましょう.そしてそれをします:
// next.config.js
module.exports = {
images: {
domains: ['opengraph.githubassets.com'],
},
};
以上です!邪魔にならないようになったので、
blurDataURL
prop の生成を開始しましょう.blurDataURL を生成する
私は MDX を使用しており、ページを静的にレンダリングしているので、すべてをフィルター処理する単純なプラグインを追加しました.
マークダウンからの画像は、それらの
width
、 height
、および blurDataURL
を計算し、小道具として渡します.// src/utils/plugins/image-metadata.ts
import imageSize from 'image-size';
import { ISizeCalculationResult } from 'image-size/dist/types/interface';
import path from 'path';
import { getPlaiceholder } from 'plaiceholder';
import { Node } from 'unist';
import { visit } from 'unist-util-visit';
import { promisify } from 'util';
// Convert the imageSize method from callback-based to a Promise-based
// promisify is a built-in nodejs utility function btw
const sizeOf = promisify(imageSize);
// The ImageNode type, because we're using TypeScript
type ImageNode = {
type: 'element';
tagName: 'img';
properties: {
src: string;
height?: number;
width?: number;
blurDataURL?: string;
placeholder?: 'blur' | 'empty';
};
};
// Just to check if the node is an image node
function isImageNode(node: Node): node is ImageNode {
const img = node as ImageNode;
return (
img.type === 'element' &&
img.tagName === 'img' &&
img.properties &&
typeof img.properties.src === 'string'
);
}
async function addProps(node: ImageNode): Promise<void> {
let res: ISizeCalculationResult;
let blur64: string;
// Check if the image is external (remote)
const isExternal = node.properties.src.startsWith('http');
// If it's local, we can use the sizeOf method directly, and pass the path of the image
if (!isExternal) {
// Calculate image resolution (width, height)
res = await sizeOf(path.join(process.cwd(), 'public', node.properties.src));
// Calculate base64 for the blur
blur64 = (await getPlaiceholder(node.properties.src)).base64;
} else {
// If the image is external (remote), we'd want to fetch it first
const imageRes = await fetch(node.properties.src);
// Convert the HTTP result into a buffer
const arrayBuffer = await imageRes.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
// Calculate the resolution using a buffer instead of a file path
res = await imageSize(buffer);
// Calculate the base64 for the blur using the same buffer
blur64 = (await getPlaiceholder(buffer)).base64;
}
// If an error happened calculating the resolution, throw an error
if (!res) throw Error(`Invalid image with src "${node.properties.src}"`);
// add the props in the properties object of the node
// the properties object later gets transformed as props
node.properties.width = res.width;
node.properties.height = res.height;
node.properties.blurDataURL = blur64;
node.properties.placeholder = 'blur';
}
const imageMetadata = () => {
return async function transformer(tree: Node): Promise<Node> {
// Create an array to hold all of the images from the markdown file
const images: ImageNode[] = [];
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;
width
、 height
、および blurDataURL
小道具を計算するために必要なことはこれだけです.これを使うにはプラグイン、ブログ投稿自体をレンダリングする
pages/blog/[slug].tsx
ページにジャンプしましょう.export const getStaticProps: GetStaticProps<Props> = async (ctx) => {
// get the post slug from the params
const slug = ctx.params.slug as string;
// get the post content. readBlogPost just reads the file contents using fs.readFile(postPath, 'utf8')
const postContent = await readBlogPost(slug);
// Use the gray-matter package to isolate the markdown matter (title, description, date) from the content
const {
content,
data: { title, description, date },
} = matter(postContent);
return {
props: {
// use the serialize method from the 'next-mdx-remote/serialize' package to compile the MDX
source: await serialize(content, {
mdxOptions: {
// pass the imageMetadata utility function we just created
rehypePlugins: [imageMetadata],
},
}),
title,
description,
date,
slug,
},
};
};
以上です!これを実際に確認するには、MDX イメージ コンポーネントに
console.log
を配置し、小道具を確認します.これが私の MDX イメージ コンポーネントです.
const Image = (props) => {
return (
<NextImage {...props} layout='responsive' loading='lazy' quality={100} />
);
};
props
オブジェクトは、実際には node.properties
ファイル内の image-metadata.ts
オブジェクトです.この記事を読んでいる場合は、既にぼかし効果が発生していることがわかるはずです.
このソリューションは、MDX 以外のさまざまなシナリオにも適用できます.取得することに注意してください
画像データ (
!isExternal
の image-metadata.ts
if ステートメント) はサーバー側の機能です.Node.JS の
fs
パッケージを使用しているためです.何らかの理由でクライアント側でこれを行う必要がある場合は、画像データの取得方法を変更する必要があります.
システム全体を確認したい場合は、私のウェブサイトのソースを確認してください: nikolovlazar/nikolovlazar.com
Note: if you're applying the blur effect on user submitted images, make sure you know where those images
will be stored, and don't forget to register the domain in thenext.config.js
file.
Reference
この問題について(Next.js でリモート画像用の blurDataURL を生成する), 我々は、より多くの情報をここで見つけました https://dev.to/nikolovlazar/generating-blurdataurl-for-remote-images-in-nextjs-51mgテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol