문제 상황
React에서는 SVG를 임포트해서 바로 컴포넌트처럼 사용할 수 있었다.
하지만 Next.js에서는 해당 기능을 지원하지 않았다.
Next.js에서는 <img/> 태그의 src 속성에 SVG 경로를 넣어 사용했고 이에 따라 SVG 스타일 커스터마이징이 용이하지 않았다.
이 글에서는 Next.js에서 SVG 파일을 컴포넌트로 사용하는 방법을 설명한다.
문제 원인
위 문제 상황의 원인은 Next.js의 Webpack 기본 설정 때문이다.
1. Create React App(CRA)는 기본적으로 SVGR을 포함하여 .svg 파일을 React 컴포넌트로 처리할 수 있었다.
2. Next.js는 성능 최적화와 커스터마이징에 초점을 맞췄기 때문에 SVGR이 포함되어 있지 않다.
3. Next.js는 Webpack을 사용해 프로젝트를 번들링한다.
4. Webpack의 기본 동작에서는 .svg 파일을 정적 파일로 간주하고, URL 경로로 처리합니다. 즉, SVG 파일은 브라우저에서 로드할 수 있는 리소스로 취급됩니다.
5. React 컴포넌트로 SVG를 사용하려면 .svg를 JavaScript로 변환해야 하는데, Webpack의 기본 설정에는 이 기능이 포함되어 있지 않다.
해결 방법
SVGR 설치
npm install @svgr/webpack --save-dev
next.config.js 수정
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: [
{
loader: '@svgr/webpack',
options: {
icon: true,
},
},
],
});
return config;
},
};
module.exports = nextConfig;
Next.js 재시작
npm run dev
RVGR 임포트하여 사용하기
import TestSvg from "@/assets/Test.svg"
...
<TestSvg/>
Next 13 버전 이전 또는 웹팩 번들러 사용자는 위 과정에서 오류 없이 잘 해결되었을 것이다.
하지만 필자는 Next.js 15.0.3 사용중이었고 해당 버전은 터보팩을 기본 번들러로 사용하고 있기에 오류가 발생했다.
필자는 아래와 같은 방법을 시도했으나 모두 실패하였다.
1. img로 src 불러와 img 내에서 스타일링 하기
2. NEXT_USE_TURBOPACK=0 npm run dev 으로 터보팩 번들러를 웹팩 번들러로 변경하기
3. img로 src 불러와 부모 스타일링 상속받기
해결 방법2
이에 필자는 터보팩을 사용중인 독자를 위해 3가지 해결방법을 제시한다.
1. Next.js 다운그레이드
2. SVG 자체 수정(fill, stroke, ...)
3. SVG 컴포넌트화
import { IconPropsType } from "@/types/icon.type";
import styled from "styled-components";
const Pentagon = ({ fill, stroke, strokeWidth }: IconPropsType) => {
return (
<Svg
width="32"
height="31"
viewBox="0 0 32 31"
fill={fill}
stroke={stroke}
strokeWidth={strokeWidth}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16.2939 1.59549L16 1.38197L15.7061 1.59549L1.44026 11.9602L1.14637 12.1738L1.25862 12.5193L6.70769 29.2898L6.81995 29.6353H7.18322H24.8168H25.1801L25.2923 29.2898L30.7414 12.5193L30.8536 12.1738L30.5597 11.9602L16.2939 1.59549Z"
/>
</Svg>
);
};
export default Pentagon;
const Svg = styled.svg`
stroke: ${(props) => `var(${props.stroke})`};
`;
필자는 터보팩과 웹팩의 성능차이가 크다는 점과 SVG 자체 수정 시 유지보수 비용이 높아진다는 점 때문에 3번인 SVG 컴포넌트화를 선택했으며 코드는 위와 같다.
해당 코드는 SVG 파일의 코드를 모두 복붙해 컴포넌트로 만든 후 props로 SVG를 스타일링할 값을 받아 스타일링을 수행한다.
다소 원시적인 방법을 제시하여 정말 죄송합니다.
더 좋은 방법을 아시는 독자님께서는 댓글로 설명 부탁드립니다.😥
끝.
추가
Q. 생각해보니 터보팩에서 svgr을 지원하지 않는데 왜 MUI 아이콘은 SVGR과 스타일링이 가능할까?
A.
좋은 질문입니다! **Material-UI(MUI)** 아이콘은 Next.js의 Turbopack에서도 React 컴포넌트로 바로 사용할 수 있는 이유는 다음과 같은 차이 때문입니다:
---
### **1. MUI 아이콘은 NPM 패키지로 제공**
- **MUI 아이콘**은 실제 SVG 파일을 직접 사용하는 것이 아니라, `@mui/icons-material` 패키지 내에서 이미 **React 컴포넌트로 변환된 상태**로 제공됩니다.
- 즉, MUI 아이콘은 `@svgr/webpack` 같은 설정 없이도 **React 컴포넌트로 설계된 라이브러리**이기 때문에 별도의 번들러 설정이 필요 없습니다.
---
### **2. React 컴포넌트로 변환된 SVG**
`@mui/icons-material` 내부적으로 **SVGR**(SVG to React Component 변환 도구)을 사용하여 SVG 파일을 React 컴포넌트로 변환한 상태로 패키지화되었습니다. 이 패키지를 사용하면 이미 React 컴포넌트로 변환된 아이콘을 바로 임포트하여 사용할 수 있습니다.
#### MUI 아이콘 예제:
```javascript
import MenuIcon from "@mui/icons-material/Menu";
const AppBar = () => (
<div>
<MenuIcon style={{ color: "blue", fontSize: 50 }} />
</div>
);
export default AppBar;
```
- 위 예제에서 `MenuIcon`은 이미 React 컴포넌트로 정의되어 있어 스타일링(`style`, `className`)을 바로 적용할 수 있습니다.
- MUI 아이콘은 `fontSize`나 `color`와 같은 추가적인 속성도 제공하여 더 편리하게 사용할 수 있습니다.
---
### **3. SVG 직접 사용과의 차이점**
SVG 파일을 직접 사용하는 경우에는 React 컴포넌트로 변환되지 않은 **정적 리소스**로 간주되므로, 이를 React 컴포넌트처럼 사용하려면 별도의 설정(`@svgr/webpack`)이 필요합니다.
#### SVG 직접 사용:
```javascript
// Turbopack 환경에서는 아래와 같은 임포트가 지원되지 않음
import PentagonIcon from "@/assets/pentagon.svg";
const AppBar = () => (
<div>
<PentagonIcon />
</div>
);
```
- Turbopack은 SVG를 React 컴포넌트로 변환하지 않고, 단순히 정적 파일로 처리합니다.
- 따라서 스타일링이 불가능하거나, 추가 설정이 필요합니다.
#### MUI 아이콘 사용:
```javascript
import MenuIcon from "@mui/icons-material/Menu";
const AppBar = () => (
<div>
<MenuIcon style={{ color: "blue", fontSize: "50px" }} />
</div>
);
```
- MUI 아이콘은 이미 React 컴포넌트로 제공되므로, 바로 스타일링이 가능하며 번들러(Turbopack 또는 Webpack)와 무관하게 동작합니다.
---
### **4. 스타일링 가능 이유**
MUI 아이콘은 React 컴포넌트이기 때문에:
- `style` 속성
- `className` 속성
- `styled-components`, `emotion` 등의 스타일링 라이브러리
을 통해 자유롭게 스타일을 조작할 수 있습니다.
#### 예제: `styled-components`로 MUI 아이콘 스타일링
```javascript
import styled from "styled-components";
import MenuIcon from "@mui/icons-material/Menu";
const StyledMenuIcon = styled(MenuIcon)`
color: red;
font-size: 50px;
`;
const AppBar = () => (
<div>
<StyledMenuIcon />
</div>
);
export default AppBar;
```
---
### **5. 결론**
1. **MUI 아이콘은 이미 React 컴포넌트로 패키징**되어 있기 때문에 별도의 변환 과정 없이 바로 사용할 수 있습니다.
2. **SVG 직접 사용**은 React 컴포넌트로 변환되지 않은 정적 파일을 처리하기 때문에 번들러(Turbopack 또는 Webpack) 설정이 필요합니다.
3. MUI 아이콘은 스타일링이 가능한 React 컴포넌트이므로 Turbopack과도 완벽히 호환됩니다.
따라서, MUI 아이콘은 Next.js에서 특별한 설정 없이도 바로 사용할 수 있는 것입니다. Turbopack 환경에서도 문제없이 동작하는 이유이기도 합니다.
'프론트엔드 > Next.js' 카테고리의 다른 글
[Next.js] Next.js 환경에서 MUI integration 방법 + MUI 전역 스타일링 방법 (1) | 2024.12.03 |
---|---|
[Next.js] "use client"는 CSR 방식과 동일할까? (1) | 2024.12.02 |
[Next.js] Next.js + Styled-components 적용하기 (0) | 2024.11.30 |
Next.js + Supabase 프로젝트에서 NEXT_PUBLIC 환경 변수에 anon 키를 저장했을 경우에 보안 위협성 (0) | 2024.11.26 |
[Next.js] 서버 컴포넌트 VS 클라이언트 컴포넌트 (0) | 2024.08.14 |