์ด๋ฒ ํ๋ก์ ํธ์์ emotion์ผ๋ก ์คํ์ผ๋ง์ ํ๊ธฐ๋ก ํ๋๋ฐ ํน๋ณํ ์ด์ ๊ฐ ์๋ ๊ฒ์ ์๋๊ณ ๊ทธ๋ฅ ๋ค๋ค ๋ง์ด ์ฐ๊ธธ๋ ์ฌ์ฉํด๋ดค๋ค.
ํ ๋ฒ๋ ์ฌ์ฉํด๋ณธ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ ๊ฑฑ์ ํ๋๋ฐ ์ฌ๊ฑธ ๊ทธ๋ฅ ๋ฌธ๋ฒ์ด styled-components๋ ๋๊ฐ์๋ค!
์ฐพ์๋ณด๋ ๋ ๋ค CSS-in-JS์ sass ๋ฌธ๋ฒ์ ์ฌ์ฉํด์ ์ฐจ์ด๋ฅผ ๋ชป๋๊ผ๋ ๊ฒ์ด๋ค.
CSS-in-JS
: JS ์์์ css์ฝ๋๋ฅผ ๊ด๋ฆฌ
css ์ฝ๋๋ฅผ ๋ณ์๋ก ๊ด๋ฆฌํ ์ ์์ผ๋ฉฐ ๋์ ์ผ๋ก css ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ฝ๋ค๋ ์ฅ์ ์ด ์์
emotion์ด styled-components๋ณด๋ค ์กฐ๊ธ ๋ ๊ฐ๋ณ๊ณ ๋น ๋ฅด๋ค๊ณ ํ๋ค. ๊ทธ๋ฆฌ๊ณ SSR์์ emotion์ ๋ณ๋ ์ค์ ์์ด ๋์ํ์ง๋ง Styled-components๋ ServerStyleSheet ์ค์ ์ ํด์ผํ๋ค๊ณ ํ๋ค.
์ฐธ์กฐ ๋ธ๋ก๊ทธ: https://intrepidgeeks.com/tutorial/whats-the-difference-between-a-styled-component-and-emotion
๊ทธ๋ผ emotion์ด ๋ญ์ง๋ ์์๋ดค์ผ๋ ์ด์ ์ฌ์ฉํด๋ณด๋๋ก ํ์
yarn๋ npm ์ค ํธํ๊ฑธ๋ก ๊ณจ๋ผ์ฐ๋ฉด ๋๋ค. ๋จ ํผ์ฉ์ ํผํ์!
yarn add @emotion/react
yarn add @emotion/styled
๋๋
npm install --save @emotion/react
npm install --save @emotion/styled
ํ
๋ง ์ค์ ๋ ๊ฐ๋จํ๋ค
๋จผ์ TypeScript๋ฅผ ์ฌ์ฉํ๊ณ ์์ผ๋ฏ๋ก emotion.d.ts
์์ ํ์ํ ์๊ณผ ํฐํธ ํ์
์ ์ง์ ํ๋ค.
import '@emotion/react';
declare module '@emotion/react' {
export interface Theme {
color: {
purple: string;
// ...
skyblue: string;
};
font: { main: string };
}
}
์ต์์ ํ์ผ _app.tsx
์์ ThemeProvider๋ฅผ ์ ์ฉ์์ผ์ค๋ค.
์ด๋ ๊ฒ ํด์ผ ํ์ ์ปดํฌ๋ํธ๋ค์ด ํ
๋ง์ ์ ๊ทผํ ์ ์๋ค. โ css prop
reset.ts
์์ html ๊ธฐ๋ณธ ์คํ์ผ์ ์์ ๊ณ ์๋ก์ด ์คํ์ผ์ ๊ธ๋ก๋ฒ ์คํ์ผ๋ก ์ ์ฉํ๋ค.
import type { AppProps } from 'next/app';
import { css, Global, ThemeProvider } from '@emotion/react';
import reset from '../styles/reset';
import theme from '../styles/themes';
const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<ThemeProvider theme={theme}>
<Global
styles={css`
${reset}
`}
/>
<Component {...pageProps} />
</ThemeProvider>
);
};
export default MyApp;
๊ทธ๋ฆฌ๊ณ theme.tsx
์์ ์์ธ ์๊ณผ ํฐํธ ๊ฐ์ ์ง์ ํ๋ค
import { Theme } from '@emotion/react';
const color = {
purple: '#9268EC',
// ...
skyblue: '#93D8FF',
};
const font = { main: 'Pretendard' };
const theme: Theme = {
color: {
purple: color.purple,
// ...
skyblue: color.skyblue,
},
font: { main: font.main },
};
export default theme;
์ด์ ์ํ๋ ์ฅ์์์ ์ฌ์ฉํ๋ฉด ๋
์ฌ์ฉ์ ์ด๋ฐ์์ผ๋ก!
color: ${(props) => props.theme.color.skyblue};
์ฒซ SSR ํ๋ก์ ํธ๋ค๋ณด๋ SEO์ ์ ๊ฒฝ์ ๋ง์ด ์ฐ๊ณ ์ถ์๋ค. ๋ ์ด์ฌํ ๋ง๋ค ํ์ ์ด ๋ฌปํ๋ฉด ์์ฌ์ฐ๋๊นใ ใ
๊ฒ์์์ง์ต์ ํ(SEO)
: ๊ฒ์์์ง์ด ์๋ฃ๋ฅผ ์์งํ๊ณ ์์๋ฅผ ๋งค๊ธธ ๋ ํ๊ทธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์ ํค์๋ ์ฐ์ ์์๋ฅผ ํ์ ํ๊ธฐ ๋๋ฌธ์ ๋ชฉ์ ์ ๋ถํฉํ ํ๊ทธ๋ฅผ ์ฌ์ฉํด์ผ ๊ฒ์ ๊ฒฐ๊ณผ ๋ ธ์ถ์ ์ ๋ฆฌ (Div์์ ๋ฒ์ด๋๊ธฐ)
ํฌ๋กฌ ๊ฐ๋ฐ์๋๊ตฌ์ Lighthouse์ SEO 100์ ์ ๋ชฉํ๋ก ํญ ์ ๋ชฉ๋ฅผ mbti type์ ๋ฐ๋ผ ๋ณ๊ฒฝํด ๋ณด์๋ค.
ํญ ์ ๋ชฉ ๋ณ๊ฒฝ์ SEO์ ๋ง๊ฒ ์ฌ์ดํธ๋ฅผ ์ต์ ํํ๋ ๋ฐฉ๋ฒ ์ค ํ๋๊ธฐ๋ ํ๊ณ ์ฌ๋ฌ ํญ์ ์ด์ด๋์์ ๋ ๋ธ๋ผ์ฐ์ ํ์์ค์์ ๊ด๋ จ ์ฌ์ดํธ๋ฅผ ๋น ๋ฅด๊ฒ ์๋ณํ๋ ๋ฐ ๋์์ด ๋๋ค.
ํญ ์ ๋ชฉ์ ๋ณ๊ฒฝํ๋ ๋ฐฉ๋ฒ๋ ์งฑ ๊ฐ๋จํ๋ค
seo.tsx
import Head from 'next/head';
interface IType {
type: string;
}
const SEO = ({ type }: IType) => {
return (
<Head>
<title> {type} | Gift MBTI</title>
</Head>
);
};
export default SEO;
import Head from 'next/head';
์ ์๋ฒ๋ก ๋ถํฐ <head>
ํ๊ทธ๋ฅผ ๋ฐ์ ์์ค๋ค
Head์ ๋ํด ๋ ๊ถ๊ธํ๋ค๋ฉด ์๋ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ์กฐํด๋ด๋ ์ข์ ๊ฒ ๊ฐ๋ค!
https://velog.io/@cyranocoding/NEXT-HEAD-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC
์ฌ์ฉํ ๋ ์ํ๋ ํ์ด์ง์์ importํด ์ฌ์ฉํ๋ฉด ๋๋ค
<SEO type={type} />
์ด๋ ๊ฒ ๊ธฐ๋ณธ ์ค์ ์ ํด๋๊ณ ์คํ์ผ๋ง์ ์งํํ๋๋ฐ ๋์์ด๋์ ํ์
ํ๋ ๋งํผ ์์ ์น์ด ์์ฑ๋์ง๋ง ๊ทธ๋งํผ ์คํ์ผ๋ง๋ ์ด๋ ค์ ๋ค.
๊ทธ๋๋ ์์ฑ๋ ํ์ด์ง๋ฅผ ๋ณด๋ฉด ๋ฟ๋ฏํ๋คใ
ใ
๋นจ๋ฆฌ ์์ฑํด์ ์น๊ตฌ๋คํํ
๋ฟ๋ฆฌ๊ณ ์ถ๋ค!