231017(ํ) ์ฑ์ฅ
๐ค ์ฑ์ฅ์ผ์ง 7.0
์ฑ
ํ๋ณตํ ์ด๊ธฐ์ฃผ์์(์จ์ธ ๋ค์ด์ด)
์ ๋ด์ฉ์ ์๊ทน๋ฐ์ ์์ํ๋ ์๋ฐํ ์ฑ์ฅ๊ธฐ๋ก
์ด์์๋ ๊ฝ๊ณผ ์ฃฝ์ ๊ฝ์ ์ด๋ป๊ฒ ๊ตฌ๋ณํ๋๊ฐ?
์ฑ์ฅํ๊ณ ์๋ ๊ฒ์ด ์ด์ ์๋ ๊ฒ์ด๋ค.
์๋ช ์ ์ ์ผํ ์ฆ๊ฑฐ๋ ์ฑ์ฅ์ด๋ค!
โ (7.0)<์์ ๊ฐํธ>
ํ์ธ๋ง ํ์ต๋ฒ
์ ์๊ฒ ๋๋งํผ, ์ฑ์ฅ์ผ์ง๋ ์ ๋ง ๊ทธ ๋ ์ ํค์๋ ์ค์ฌ์ผ๋ก ๊ฐ๋จํ๊ฒ ์ ๋ฆฌํ๋๋ก ํ๋ค.
Next.js์์์ svg
๋ณดํต React๋ฅผ ์ฌ์ฉํ ๋๋ ์๋์ ๊ฐ์ด svg ํ์ผ์ React Component๋ก ๋ณํํด์ ์ฌ์ฉํ๊ณค ํ๋ค.
import { ReactComponent as Logo } from './logo.svg';
// <Logo />
๊ทธ๋ฐ๋ฐ Next.js์์๋ ์ด๋ ๊ฒ ์ฌ์ฉํ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. ์ด์ ๋ Next.js์์๋ svg๋ฅผ ๋ชจ๋๋ก ์ธ์ํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค. Next.js์์ svg๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์๋๋ฐ ๊ทธ ์ค 2๊ฐ์ง๋ฅผ ๊ธฐ๋กํด๋๋ค.
1. import ํ Image ์ปดํฌ๋ํธ ์ฌ์ฉ(๋น์ถ)
์ด ๋ฐฉ๋ฒ์ ์ฌ์ค ์ ๋ง ๊ฐ๋จํ๋ค. svg๋ฅผ importํ๊ณ Image ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. ํ์ง๋ง ์ด ๋ฐฉ๋ฒ์ svg๋ฅผ React Component๋ก ๋ณํํ๋ ๊ฒ์ด ์๋๋ผ ๊ทธ๋ฅ ์ด๋ฏธ์ง๋ก ์ฌ์ฉํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ svg์ ์ฅ์ ์ ์ด๋ฆด ์ ์๋ค. ์๋ฅผ ๋ค์ด, svg์ ์ด๋ฏธ์ง์ ํฌ๊ธฐ๋ ์์ ๋ฑ์ props ํน์ css ํํ๋ก ๋ณ๊ฒฝํ ์ ์๋ค. ๋ํ Next.js ๊ณต์๋ฌธ์์๋ ๋์์๋ฏ์ด Image ์ปดํฌ๋ํธ๋ก์์ ์ต์ ํ์ ์์ด์ ํจ์จ์ฑ์ด ๋จ์ด์ง๋ค.
import Logo from './logo.svg';
<Image src={Logo} />;
2. @svgr/webpack
์ฌ์ฉ
์ด 2๋ฒ์งธ ๋ฐฉ๋ฒ์ด ํํ ๊ถ์ฅ๋๋ ๋ฐฉ๋ฒ์ธ๋ฐ, ๊ทธ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค. @svgr/webpack
์ ์ฌ์ฉํ๋ฉด svg๋ฅผ React Component๋ก ๋ณํํด์ฃผ๋ webpack loader๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ์ด๋ ๊ฒ ํ๋ฉด svg๋ฅผ React Component๋ก ๋ณํํด์ ์ฌ์ฉํ ์ ์๋ค.
๊ทธ ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฒ์ ์ฐธ๊ณ ์ ๋๋ฌด ์๋์์์ด์ ๊ทธ๋๋ก ๋ฐ๋ผํ๋ฉด ๋๋ค.
๋ค๋ง, 2๊ฐ์ง ์ฃผ์์ (ํน์ ํ)์ด ์๋ค.
- ์์ ๋ฐฉ๋ฒ๋๋ก ํ๋๋ฐ, ๋ณํ๋ svg component๊ฐ ์๋ฒ ์ปดํฌ๋ํธ์์๋ ์๋ํ์ง ์๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.(
Module parse failed: Unexpected token
) ์๋์ ๊ฐ์ด ํ๋ฉด ํด๊ฒฐํ ์ ์๋ค.
webpack(config) {
// SVG ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ธฐ์กด ๊ท์น์ ๊ฐ์ ธ์ค๊ธฐ
const fileLoaderRule = config.module.rules.find(rule => rule.test?.test?.('.svg'));
config.module.rules.push(
// ?url๋ก ๋๋๋ svg ๊ฐ์ ธ์ค๊ธฐ์๋ง ๊ธฐ์กด ๊ท์น์ ์ ์ฉ
{
...fileLoaderRule,
test: /\.svg$/i,
resourceQuery: /url/, // *.svg?url
},
// ๋ค๋ฅธ ๋ชจ๋ *.svg ๊ฐ์ ธ์ค๊ธฐ๋ฅผ React ๊ตฌ์ฑ ์์๋ก ๋ณํ
{
test: /\.svg$/i,
// issuer: /\.[jt]sx?$/, // *.svg๋ฅผ ๊ฐ์ ธ์ค๋ ํ์ผ => ์ด ๋ถ๋ถ์ ์ญ์ ํ๋ค.
resourceQuery: { not: /url/ }, // *.svg?url ์ ์ธ
use: ['@svgr/webpack'],
},
);
// svg์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ํ์ผ๋ฏ๋ก *.svg๋ฅผ ๋ฌด์ํ๋๋ก ํ์ผ ๋ก๋ ๊ท์น์ ์์
fileLoaderRule.exclude = /\.svg$/i;
return config;
},
์์ ์ฃผ์์๋ ์๋ฏ์ด issuer
๋ฅผ ์ญ์ ํด์ผ ํ๋ค. ์์ฃผ ์ ํํ ์ด์ ๋ ์๋์ง๋ง ์ฐพ์๋ณด๋ issuer๊ฐ svg ํ์ผ์ ๊ฐ์ ธ์ค๋ ํ์ผ
์ ๋ช
์ํ๋ ๊ฒ์ธ๋ฐ, ์ค์ ์๋ฒ์์ ์คํ๋๋ ์๋ฒ ์ปดํฌ๋ํธ๋ ๋น๋๋ ํ์ผ์ด๊ธฐ ๋๋ฌธ์ ๋ช
์๋ ํ์ผ์ด ์์ด์ ๊ทธ๋ฐ ๊ฒ ๊ฐ๋ค.
(์ถ๊ฐ) ์ข๋ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋ ์ค ๋ฌธ์ ๊ด๋ จ ๊นํ ์ด์ ์ฝ๋ฉํธ์์ ์๋์ ๊ฐ์ด ์ ์ฉํด์๋ ํด๊ฒฐํ ์ ์์๋ค.
webpack(config, { isServer }) {
// SVG ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ธฐ์กด ๊ท์น์ ๊ฐ์ ธ์ค๊ธฐ
const fileLoaderRule = config.module.rules.find(rule => rule.test?.test?.('.svg'));
config.module.rules.push(
// ?url๋ก ๋๋๋ svg ๊ฐ์ ธ์ค๊ธฐ์๋ง ๊ธฐ์กด ๊ท์น์ ์ ์ฉ
{
...fileLoaderRule,
test: /\.svg$/i,
resourceQuery: /url/, // *.svg?url
},
// ๋ค๋ฅธ ๋ชจ๋ *.svg ๊ฐ์ ธ์ค๊ธฐ๋ฅผ React ๊ตฌ์ฑ ์์๋ก ๋ณํ
{
test: /\.svg$/i,
issuer: fileLoaderRule.issuer, // *.svg?url ์ ์ธ
resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // *.svg?url ์ ์ธ
use: ['@svgr/webpack'],
},
);
// svg์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ํ์ผ๋ฏ๋ก *.svg๋ฅผ ๋ฌด์ํ๋๋ก ํ์ผ ๋ก๋ ๊ท์น์ ์์
fileLoaderRule.exclude = /\.svg$/i;
return config;
},
๋ณด๋๊น svg๋ฅผ ๊ฐ์ ธ์ค๋ ํ์ผ์ ๋ช
์ํ ๋, ์์์ ์ ์ฉํ *.svg?url
๊ท์น๊น์ง ํฌํจ๋ผ์ ๋ช
์๋๋ ๊ฒ ๊ฐ๋ค. ๊ทธ๋์ issuer
๋ฅผ fileLoaderRule.issuer
๋ก ๋ช
์ํด์ฃผ๋ฉด ํด๊ฒฐ๋๋ค.
- svg component์ ๋ํ custom ํ์ ์ ์ํด์ฃผ๊ธฐ
๊ธฐ๋ณธ์ ์ผ๋ก ์์ ๊ณผ์ ์ ๊ฑฐ์ณ์ svg๋ฅผ react component์ฒ๋ผ ์ฌ์ฉํ๊ฒ ๋๋ฉด ์ ์๋ํ๋ค! ๋ค๋ง ์์ฌ์ด ์ ์ ํด๋น ์ปดํฌ๋ํธ์ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ฆฌ๋ฉด any
ํ์
์ด ๋์จ๋ค๋ ๊ฒ์ด๋ค. ์ด ๋ถ๋ถ์ ์ง์ ํ์
์ ์ ์ธํด์ค์ผ๋ก์จ ํด๊ฒฐํ ์ ์๋ค. ๋๊ฐ์ ๊ฒฝ์ฐ root ๋๋ ํ ๋ฆฌ์ svg-component.d.ts
๋ฅผ ๋ง๋ค์ด์ฃผ์๋ค.
declare module '*.svg' {
import React from 'react';
const svg: React.FC<React.SVGProps<SVGSVGElement>>;
export default svg;
}
๊ทธ๋ฆฌ๊ณ tsconfig.json
์ ์๋์ ๊ฐ์ด ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
{
"compilerOptions": {
"include": ["svg-component.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"]
}
}
์ด์ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ ค๋ณด๋ฉด React.FC<React.SVGProps<SVGSVGElement>>
ํ์
์ด ์ ๋์ค๋ ๊ฑธ ํ์ธํ ์ ์๋ค.(๊ทธ๋๋ any๊ฐ ๋์ค๋ฉด vscode ์ฌ์์ํด๋ณด๊ธฐ~!)
๐ ํ๊ณ
์ค๋ ํ๋ฃจ๊ฐ ๋ญ๊ฐ ํ์ฐ์ ํ๊ณ ์ง๋๊ฐ๋คโฆ ์ ์ ๋ฐ์ง ์ฐจ๋ฆฌ๊ณ ์ด์์ผ๊ฒ ๋ค์!!! ์๊ฐ์ ์ธ์งํ๋ฉด์ ์ด์!