일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- hokeys
- SWIFT
- 개발
- 자료구조
- 개발자
- react
- 리액트
- Svelte
- javascript
- 힛잇
- 비동기
- queue
- Hitit
- HTML
- IOS
- 자스민
- 계명대
- 호키도키
- 자바스크립트
- TDD
- 계명대 이종호
- 호키스
- jest
- 자바스크립트 자료구조
- 이종호
- 스벨트
- 리액트 예제
- hokidoki
- data structure
- 스위프트
- Today
- Total
Dog foot print
Next.js StaticImageData With Storybook 본문
nextJs/Image를 storybook에서 사용 할 때.
Next.js
에서는 import
키워드로 소스 파일로 끌어 올 때 StaticImageData
라는 타입으로 전달 받게 된다. 이 타입의 형태는 다음과 같다.
interface StaticImageData {
src: string
height: number
width: number
blurDataURL?: string
}
보통 이 StaticImageData
를 이용해서,image
태그를 사용하지 않고 next/Image
와 함께 사용한다. Next.js/Image는 이미지의 경로를 문자열
혹은 StaticImageData
타입을 Props.src
로 받기 때문에, 아래와 같이 보통 작성한다.
import Image from "next/image";
import LogoImage from "./Logo.png"
export default function Logo(){
return <Image src={LogoImage} />
}
이 때 스토리북을 실행시켜, LogoImage
를 확인하면 다음과 같이 static/media
접두사를 붙여, 해당 이미지의 경로를 제공한다.
"static/media/src/Atoms/Image/Logo.png"
위의 LogoImage
를 스토리 북으로 내보내기 하면, 다음과 같이 이미지를 처리 할 수 없다고 에러가 발생한다.
이는 next/Image가 경로를 받아 최적화를 실행하려고 하였지만 nextjs가 실행되어 있지 않기 때문에 발생하는 에러이다. 이를 해결 하려면 스토리북에서 최적화를 실행하지 않고 이미지 경로를 그대로 가져 올 수 있게 해야한다.
/storybook/preview.js
import * as NextImage from "next/image";
// storybook 환경에선 next image 최적화를 쓰지 않기에 해제해줘야함.
const OriginalNextImage = NextImage.default;
Object.defineProperty(NextImage, "default", {
configurable: true,
value: (props) => (
<OriginalNextImage
{...props}
unoptimized
loader={({ src }) => src}
/>
),
});
unoptimized
옵션을 true로 주게되면, next/Image는 이미지의 퀄리티나 크기를 조정하지 않고 기본 상태로 전달하게 된다. 이 옵션에 관련된 자세한 내용은 링크를 참조하면 된다. next/image | Next.js
loader
옵션은 Image경로를 호출 할 때, next/Image가 아닌 다른 곳에서 최적화를 시켜줄 수 있는 경로로 변경 할 수 있는 옵션이다. 그렇기에 그냥 다른 곳으로 전달되지 않고 이미지를 보여 줄 수 있도록 src를 바로 넘겨주는 것이다. 이 옵션에 관련된 자세한 내용은 링크를 참조하면 된다. next/image | Next.js
정적 이미지를 base64로 처리하고 싶을 때.
Note : Webpack의 비교적 최신버전에는 file-loader와 url-loader가 asset
이라는 이름의 모듈로 내장되어 있다. 여기서는 webpack5를 기준하여, 작성되었다.
크기에 따라 정적 이미지를 경로가아닌 base64로 처리하고 싶다면, webpack
의 asset/inline
과 같은 모듈을 사용하면된다.
const path = require("path")
const webpackFinal = async (config, { configType }) => {
...
config.module.rules.push({
test: /\.(png|jpg|gif)$/i,
type: "asset",
parser : {dataUrlCondition : {maxSize 1024 * 4}} //4Kb
})
...
return config;
}
module.exports = {
...
webpackFinal
}
위와 같이 아셋 모듈을 추가하면 다음과 같이 정적이미지 크기에 따라 경로가 아닌dataUrl
로 변경된다.
정적 이미지를 StaticImageData 형식으로 처리하고 싶을 때.
Next/image
의 src는 StaticImageData
타입 뿐만아니라, string
타입으로 사용 가능하기 때문에, 위의 처리가 되었을 때, 작동에 문제가 없다. 그러나, 어떤 사유로 StaticImageData
를 사용해야 하는 이유가 존재할 때, 다음과 같이 처리하여, 타입을 적용 시킬 수 있다.
StaticImageData
타입은 자바스크립트의 객체처럼 취급되기 때문에, 기존에 존재하던 asset
과 같은 모듈을 사용 할 수 없고, 이미지 포맷을 객체타입으로 변환할 수 있는 모듈을 따로 제작해야한다.
Image로 부터, width, height를 추출하기 위해서 buffer-image-size
라이브러리를 설치한다.
yarn add -D buffer-image-size
이미지 데이터 처리를 위한 모듈을 작성한다. (해당 모듈의 첫번째 인자로 파일의 소스값이 전달되는데, 바이너리값 형태의 문자열이 들어오지만 어딘가 깨진것 같다. 이 값을 이용해 정상적인 버퍼로 컨버팅 하는 방법을 안다면 댓글 부탁드립니다.)
./storybook/StaticImageData
const path = require("path");
const fs = require("fs");
const sizeOf = require("buffer-image-size");
module.exports = function (source) {
const buffer = fs.readFileSync(this.resourcePath);
const { width, height, type } = sizeOf(buffer);
const prefix= path.resolve(__dirname,"../");
let src = `/static/media` + this.resourcePath.replace(prefix,"");
const staticImport = {
src,
width,
height
}
return `export default ${JSON.stringify(staticImport)}`
}
./storybook/main.js
const path = require("path")
const webpackFinal = async (config, { configType }) => {
...
config.module.rules.push({
test: /\.(png|jpg|gif)$/i,
type: "javascript/esm",
use: [
{
loader: path.resolve(__dirname, "./StaticImageData.js"),
},
],
})
...
return config;
}
module.exports = {
...
webpackFinal
}
위와 같이 작성하고 정적 임포트된 이미지들을 콘솔로 찍어보면, staticImageData
형태로 제공된다.
만약 크기에 따라 base64
로 변경할 수 있도록 하고 싶다면 다음과 같이 크기에 대한 옵션을 설정 할 수 있도록 한다.
./storybook/main.js
const path = require("path")
const webpackFinal = async (config, { configType }) => {
...
config.module.rules.push({
test: /\.(png|jpg|gif)$/i,
type: "javascript/esm",
use: [
{
loader: path.resolve(__dirname, "./StaticImageData.js"),
options: {
inlineLimit: 1024 * 4
}
},
],
})
...
return config;
}
module.exports = {
...
webpackFinal
}
./storybook/StaticImageData
const path = require("path");
const fs = require("fs");
const sizeOf = require("buffer-image-size");
module.exports = function (source) {
const {inlineLimit =(1024 * 4) } = this.getOptions();
const buffer = fs.readFileSync(this.resourcePath);
const { width, height, type } = sizeOf(buffer);
let src = ""
if(Buffer.byteLength(buffer) <= inlineLimit){
const encoded = buffer.toString("base64");
src = `data:/image/${type};base64,${encoded}`
}else{
const prefix= path.resolve(__dirname,"../");
src =`/static/media` + this.resourcePath.replace(prefix,"");
}
const staticImport = {
src,
width,
height
}
return `export default ${JSON.stringify(staticImport)}`
}
위와 같이 작성 후, 실행해보면 이미지 크기에 따라 src
프로퍼티가 dataURL로 처리된다.
'REACT' 카테고리의 다른 글
redux-toolkit은 무엇을 해결하려고 했는가 ? (0) | 2023.07.24 |
---|---|
useMemo 및 memo 조금 더 자세히 사용해보기 (0) | 2023.04.11 |
useContext 조금 더 자세히 사용해보기 (0) | 2023.03.30 |
useEffect 조금 더 자세히 사용해보기 (0) | 2023.03.27 |
useState 조금 더 자세히 사용해보기 (0) | 2023.03.23 |