JSX에 SVG 파일을 직접 import해서 사용하면 편리하지만 JS 번들 크기 늘어나고 불필요한 네트워크 요청 증가한다.
import NotFoundIcon from '@/assets/icons/404_sign.svg';
<img src={NotFoundIcon} alt="NotFoundLogo" className="size-40" />
아래는 랜딩 페이지의 네트워크 탭인데, 네트워크 요청의 절반이 아이콘 요청이다.
Sprite는 그래픽 리소스를 한 파일 안에 모아서 필요한 부분만 뽑아 쓰는 기법을 가리킨다.
SVG Sprite 파일을 생성하면 SVG 파일을 한 파일에 모아서 필요한 부분만 뽑아서 사용할 수 있다.
<svg />
태그를 <symbol />
로 바꾼 svg 콘텐츠를 모아 하나의<svg />
로 래핑한다.<svg />
태그로 감싼 <use />
태그의 href 속성에서 id를 사용하여 아이콘 사용한다.이를 통해 아이콘이 아무리 많아도 스프라이트 파일 한 번만 요청하면 되고, 이후엔 <use />
를 통해 각 아이콘을 재사용할 수 있어 성능과 관리 효율이 좋아진다.
프로젝트에서 사용하는 SVG 파일들을 모아 단일 SVG Sprite로 결합하는 스크립트를 작성한다.
// generateSprite.ts
import fs from 'fs';
import { globSync } from 'glob';
import { HTMLElement, parse } from 'node-html-parser';
import path from 'path';
// 프로젝트 내에 있는 모든 SVG 파일 모은다.
const svgFiles = globSync('src/shared/assets/icons/*.svg');
const symbols: string[] = [];
// 각 SVG 파일을 읽고 svg 태그를 symbol 태그로 바꾸고 필요한 속성만 취한다.
svgFiles.forEach((file) => {
const code = fs.readFileSync(file, 'utf-8');
const svgElement = parse(code).querySelector('svg') as HTMLElement;
const symbolElement = parse(`<symbol/>`).querySelector(
'symbol'
) as HTMLElement;
const fileName = path.basename(file, '.svg');
svgElement.childNodes.forEach((child) => symbolElement.appendChild(child));
symbolElement.setAttribute('id', fileName);
if (svgElement.attributes.viewBox) {
symbolElement.setAttribute('viewBox', svgElement.attributes.viewBox);
}
symbols.push(symbolElement.toString());
});
// 정적 폴더에 작성한다.
const svgSprite = `<svg>${symbols.join('')}</svg>`;
fs.writeFileSync('public/sprite.svg', svgSprite);
"scripts": {
"dev": "vite",
"generateSprite": "tsx generateSvgSprite.ts",
"build": "npm run generateSprite && tsc -b && vite build",
},
추가적인 import 없이, 아이콘 컴포넌트를 생성해서 사용한다.
interface IconProps {
name: string;
style?: string;
ariaLabel?: string;
}
export const Icon = ({ name, style, ariaLabel = name }: IconProps) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" className={style} aria-label={ariaLabel}>
<use href={`/sprite.svg#${name}`} />
</svg>
);
}
<Icon name='404_sign' style='size-40' ariaLabel="NotFoundLogo" />
아이콘으로 SVG 스프라이트를 만드는 방법
SVG Sprite 기법을 사용해 나만의 특별한 Icon 컴포넌트 개발