Next.js 블로그 제작기 (9)
신현호
블로그 제작기
목차
서론
#오늘도 블로그를 여느때와 다름없이 살펴보는데, 이미지가 처음 로딩될 때 아예 보이지 않는 문제를 찾아냈습니다.
이번 포스팅은 제가 블로그에 적용한 이미지 로딩 시 해당 이미지를 blur처리 하는 방법에 대해서 포스팅 해보도록 하겠습니다 :)
변경점
#Plaiceholder와 Sharp
#Plaiceholder 는 이름에서도 대강 유추할 수 있듯이, 말 그대로 placeholder를 만들어주는 라이브러리입니다.
Sharp 는 이미지 리사이징 라이브러리입니다. 다만 이 라이브러리 사용시 OS간의 호환성 이슈가 있는데 이건 뒤에서 마저 설명하도록 하겠습니다
Sharp의 경우 Next 프로덕션 페이지 만들때나, vercel 을 사용하고계시다면 지속적으로 Sharp를 설치하는걸 권장한다고 알려주는데요,
이는 Next에서 제공하는 Next/Image에서 sharp, squoosh 라이브러리를 사용하는데 sharp가 의존성에 없다면 squoosh를 사용하기 때문입니다.
물론 vercel을 통해 배포한다면 자기들이 알아서 해줍니다.
필요한 라이브러리는 다음과 같습니다.
bash
yarn add sharp plaiceholder @plaiceholder/next
npm install sharp plaiceholder @plaiceholder/next
next config 세팅
#패키지를 다 설치하셨다면 우선 next.config를 설정해야합니다.
js
/** @type {import('next').NextConfig} **/
import { withContentlayer } from 'next-contentlayer'
import withPlaiceholder from '@plaiceholder/next'
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
use: ['@svgr/webpack'],
})
return config
},
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'avatars.githubusercontent.com',
},
],
},
}
export default withPlaiceholder(withContentlayer(nextConfig))
nextConfig를 export해줄 때 withPlaiceholder를 감싸주면됩니다.
단, commonJS의 require로는 작동하지 않았습니다 (esm으로만 가능했습니다), 저도 이때문에 확장자를 mjs로 바꾸어 esm으로 next.config를 사용중입니다.
해당 내용에 대해서 자세히 알고 계시는분은 댓글 남겨주시면 감사하겠습니다 :)
설정을 마쳤다면 다음 스텝으로 넘어갈 수 있습니다.
Next/Image에 placeholder로 blur된 이미지 적용하기
#tsx
<Image
src={src}
alt={src}
width={img.width}
height={img.height}
placeholder="blur"
/>
공식 문서에서 정적인 이미지는 단순하게 placeholder='blur' 이것만 해줘도 된다고 하는데, 저는 뭐가 문제인지 그건 안됐습니다.
Next/Image에서는 placeholder 옵션을 위한 blurDataURL 속성도 받는데 우리는 이 옵션을 사용할 것 입니다.
이 blurDataURL는 그냥 이미지 src를 넣어주면 안되고, base64로 처리된 이미지를 넣어줘야합니다.
이때 여기에서 이미지를 base64로 처리해주기 위해서 plaiceholder 라이브러리를 사용합니다. (plaiceholder가 sharp 기반이라 같이 설치해야합니다.)
tsx
import fs from 'node:fs/promises'
import path from 'node:path'
import { getPlaiceholder } from 'plaiceholder'
const getBlurredData = async (imgSrc: string) => {
const buffer = await fs.readFile(path.join('./public', imgSrc))
const {
metadata: { height, width },
...plaiceholder
} = await getPlaiceholder(buffer, { size: 10 })
return {
...plaiceholder,
img: { imgSrc, height, width },
}
}
export default getBlurredData
fs모듈과 path를 사용해서 이미지의 path를 buffer 변수에 넣어주고, Next/Image에 기본적으로 들어가는 width와 height를 받아와줬습니다.
그리고 plaiceholder 라이브러리의 getPlaiceholder를 사용하여 해당 buffer와 placeholder의 사이즈를 넣어줍니다. 기본값은 4지만 저는 커스텀 값을 넣어줬습니다.
tsx
const getBlurredData = async (imgSrc: string) => {
const buffer = await fs.readFile(path.join('./public', imgSrc))
const { base64 } = await getPlaiceholder(buffer, { size: 10 })
return base64
}
width와 height같은 속성이 필요하지 않으시다면 위의 방법으로도 가능하겠네요
그리고 로딩되기 전 blur된 이미지를 보여주는 img 태그를 컴포넌트화시켰습니다.
tsx
import getBlurredData from '@/utils/getBlurredData'
import Image from 'next/image'
export default async function ImgWithPlacehlder({
src,
tailwindClassNames,
}: {
src: string
tailwindClassNames: string
}) {
const { base64, img } = await getBlurredData(src)
return (
<Image
className={tailwindClassNames}
src={src}
alt={src}
width={img.width}
height={img.height}
placeholder="blur"
blurDataURL={base64}
/>
)
}
tailwindClassNames는 제가 tailwind를 사용해서 그런거고, tailwind 안쓰시는분들은 필요 없습니다.
이렇게 해주면 로딩시 해당 이미지 기반의 blur된 이미지를 보여주는 img태그를 만들어낼 수 있습니다.
적용된 모습은 다음과 같습니다!
트러블 슈팅
#Sharp의 OS 문제
#Sharp 라이브러리를 설치할 때 주의해야 하는 부분은 Sharp가 OS의 바이너리를 이용하기 때문에 OS에 따라 설치되는 모듈이 다릅니다. 단순 설치로는 해당 OS의 모듈만 받아집니다.
그렇기에 AWS 혹은 Vercel에 올려다 쓸 때 해당 OS의 모듈과 맞지 않는다면 문제가 생깁니다. 그러니 라이브러리를 다운로드할 때 사용하는 OS를 고려하여 설치하셔야 합니다.
bash
npm install --platform=linux sharp
Sharp와 yarn classic
#sharp는 yarn classic에서 일반적으로는 설치가 안됩니다. 이 때는 yarn의 버전을 무시하고 설치하는 --ignore-engines 플래그를 같이 써주시면 됩니다.
bash
yarn add sharp --ignore-engines
Could not load the "sharp" module using the linux-x64 runtime / Vercel
#Vercel에서 빌드 시 해당 오류가 발생하며 빌드에 실패하는데, issue를 확인한 결과 sharp 버전 다운그레이드를 통해 해결할 수 있었습니다.
bash
yarn upgrade sharp@0.32.6
이슈 하단을 확인해보면 node의 버전을 18.19.0으로 업데이트해서 해결되었다는 경우도 보이는데, 아닌 경우도 있다고 하니 오류가 발생했을 경우 두 방법 모두 시도해보시길 바랍니다.
참고
#신현호
Frontend Developer
프론트엔드 개발자를 꿈꾸고 있는 대학생입니다. 끊임없이 배우고 성장하는 개발자가 되기 위해 노력하고 있습니다.
블로그 제작기
총 11개의 포스트가 존재합니다.