Next.js 초기세팅( +TypeScript + Emotion (styled))
React + Styled-Components로 작업했던 프로젝트를 Next.js로 리팩토링하는데 초기 설정도 쉽지 않았다.
프론트엔드에서 중요하다고 생각되는 next.js와 typescript를 알아가고 싶은 마음으로 세팅을 시작하게 되었다.
📎 Reference https://snupi.tistory.com/203
처음에 VSCode를 열고 desktop에서 작업할 폴더를 만들고 싶어 cd desktop을 한 다음
TypeScript 기반으로 Next.js 를 설치했다.
명령어에서 .은 vscode에 열려 있는 폴더 기준으로 생성하겠다는 의미다.
yarn create next-app *$*{*프로젝트 폴더명/.}* --typescript
그러면 아래와 같이 선택지가 나온다.
Tailwind Css 말고 Emotion 쓰려고 No 했고, 다른 건 다 권장해주는 대로 써보고 싶어서 Yes!
App Router는 낯설었는데 좋은 글을 발견하게 되어 써보고 싶어 Yes했고,
import alias는 전에 프로젝트 했을 때 상대경로가 아닌 절대경로가 더 편함을 경험해서 Yes로 해주었다.
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias? … No / Yes
✔ What import alias would you like configured? … @/*
설치가 끝나고 yarn dev 명령어를 실행하면 브라우저에서 작동하는 걸 볼 수 있었다.
yarn dev
- Eslint & Prettier
.eslintrc.json에 typescript 관한 규칙을 찾아보고 추가했다.
prettier도 설치하고 .prettierrc.json에 규칙을 추가했다.
📎 Reference https://findmypiece.tistory.com/203
//.eslintrc.json
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"@typescript-eslint/no-unused-vars": "error", // 사용되지 않는 변수를 에러로 인식
"@typescript-eslint/no-explicit-any": "error" // any 타입 정의를 에러로 인식
}
}
yarn add -D prettier
//.prettierrc.json
{
"semi": false,
"trailingComma": "es5",
"singleQuote": true,
"tabWidth": 2,
"useTabs": false
}
- emotion
전에 기업 협업에 나갔을 때 사용했던 CSS-in-JS 라이브러리로 theme을 쓸 수 있고
Styled-Components에서 썼던 형태로 쓸 수 있는 점이 좋아 좀 더 친숙하게 사용하고자 적용하게 되었다.
@emotion/styled 는 styled.div형태로 쓸 수 있다고 한다.
📎 Reference https://velog.io/@godud2604/styled-components-를-emotion-으로-변환하기 https://dev-russel.tistory.com/60
yarn add @emotion/styled @emotion/react
//tsconfig.json
{
"compilerOptions": {
...
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react",
}
}
src폴더 안에 styles폴더를 만들고, global.ts, theme.ts, mixin.ts 파일을 만들었다.
- Next.js + TypeScript
global.ts 파일은 전역으로 설정할 스타일을 담는다.
font와 버튼, 링크, border-box 등 기본 설정되어 있는 부분들을 reset 했다.
theme.ts 파일은 프로젝트에서 쓰는 컬러와 주로 쓸 폰트 크기를 설정했다.
global.ts
//global.ts
import { css } from '@emotion/react';
const globalStyle = css`
* {
box-sizing: border-box;
font-size: 16px;
}
html,
body,
div,
span,
h1,
h2,
h3,
h4,
h5,
h6,
p,
a,
dl,
dt,
dd,
ol,
ul,
li,
form,
label,
table {
margin: 0;
padding: 0;
border: 0;
vertical-align: baseline;
}
body {
line-height: 1.3;
background-color: '#FFFFFF';
margin-bottom: 80px;
}
ol,
ul {
list-style: none;
}
button {
border: 0;
background: transparent;
cursor: pointer;
}
a {
text-decoration: none;
color: inherit;
}
`;
export default globalStyle;
theme.ts
//theme.ts
import { DefaultTheme } from "@emotion/react";
declare module "@emotion/react" {
export interface DefaultTheme {
fontSize: {
xxs: string;
sm: string;
base: string;
md: string;
lg: string;
};
color: {
primary_light: string;
primary_normal: string;
primary_dark: string;
//error
error: string;
//gray
gray_50: string;
gray_100: string;
gray_200: string;
gray_300: string;
gray_400: string;
gray_500: string;
gray_600: string;
gray_700: string;
gray_800: string;
gray_900: string;
//black & white
black: string;
white: string;
};
}
}
const theme: DefaultTheme = {
fontSize: {
xxs: "12px",
sm: "14px",
base: "16px",
md: "18px",
lg: "24px",
},
color: {
primary_light: "#7C21FF",
primary_normal: "#6200EE",
primary_dark: "#4A00B4",
error: "#ED3124",
gray_50: "#FAFAFA",
gray_100: "#F5F5F5",
gray_200: "#EEEEEE",
gray_300: "#E0E0E0",
gray_400: "#BDBDBD",
gray_500: "#9E9E9E",
gray_600: "#757575",
gray_700: "#616161",
gray_800: "#424242",
gray_900: "#212121",
black: "#000000",
white: "#FFFFFF",
},
};
export default theme;
- @next/font
next app을 세팅했는데 layout.tsx 파일에 next/font/google 라이브러리를 통해 폰트를 가져오는 걸 보게 되었다. @next/font 라는 라이브러리를 통해 폰트를 불러오는 글을 발견해서 따라서 적용해보게 되었다.
<aside> 📎 Reference https://velog.io/@sung-je-kim/NextJS-13v-nextfontgoogle-with-emotionreact
</aside>
yarn add @next/font
디렉토리 구성
styles 디렉토리 안에 fonts디렉토리 안에 index.tsx 와 가져올 폰트에 대한 notoSans.tsx 파일을 만든다. 원하는 폰트 두께만 불러왔다.
Google Fonts(https://fonts.google.com/ )에서 두께 같은 부분을 참고했다.
notoSans.tsx
//notoSans.tsx
import { Noto_Sans_KR } from '@next/font/google'
const bold = Noto_Sans_KR({
weight: '700',
display: 'fallback',
subsets: ['latin'],
style: 'normal',
variable: '--noto-sans_KR-bold',
fallback: ['system-ui'],
})
const regular = Noto_Sans_KR({
weight: '400',
display: 'fallback',
subsets: ['latin'],
style: 'normal',
variable: '--noto-sans_KR-regular',
fallback: ['system-ui'],
})
const extraLight = Noto_Sans_KR({
weight: '300',
display: 'fallback',
subsets: ['latin'],
style: 'normal',
variable: '--noto-sans_KR-extraLight',
fallback: ['system-ui'],
})
export {
bold as notoSansKRBold,
regular as notoSansKRRegular,
extraLight as notoSansKRExtraLight,
}
index.tsx
//index.tsx
import { css } from '@emotion/react'
import {
notoSansKRBold,
notoSansKRRegular,
notoSansKRExtraLight,
} from './notoSans'
const bold = css`
font-family: ${notoSansKRBold.style.fontFamily};
`
const regular = css`
font-family: ${notoSansKRRegular.style.fontFamily};
`
const extraLight = css`
font-family: ${notoSansKRExtraLight.style.fontFamily};
`
export { bold, regular, extraLight }
- 공통 style 적용
공통된 style 세팅을 적용하려면 layout.tsx에서 설정한다.
layout.tsx
//layout.tsx
import type { Metadata } from 'next'
import { Global, ThemeProvider } from '@emotion/react'
import globalStyle from '../styles/global'
import theme from '../styles/theme'
import { bold, regular } from '../styles/fonts/index'
export const metadata: Metadata = {
title: '뮤즈, 뮤지컬 빠른 예매',
description: '뮤지컬 자리 예매도 복잡한 절차 없이 빠르게 진행할 수 있는 뮤즈',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<>
<Global styles={globalStyle} />
<ThemeProvider theme={theme}>
<html lang="en" css={ bold }>
<body>{children}</body>
</html>
</ThemeProvider>
</>
)
}
🚨Problem
- createContext only works in Client Components. Add the "use client" directive at the top of the file to use it.
- /node_modules/@emotion/react/dist/emotion-element
📎 Reference https://yzlosmik.tistory.com/121 https://github.com/emotion-js/emotion/issues/2928
초기 세팅이 됐는데 yarn dev할 때 error를 내뿜었다.
처음엔 createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. 에 대해 찾아보니 next.js app router 를 사용할 경우, React 관련 기능을 쓰려면 클라이언트로 컴포넌트로 작성하라는 뜻이라고 한다.
layout.tsx 와 page.tsx 두 파일에 ‘use client’를 써주었다.
'use client'
export default function Home() {
return ...
}
/node_modules/@emotion/react/dist/emotion-element 관련해서도 파일에 ‘use client’ 와
함께 /** @jsxImportSource @emotion/react */ 를 추가하면 된다고 해서 따라서 써줬는데 혹시나 해서
다시 삭제해봤는데 된다.
3. Warning: Extra attributes from the server: data-new-gr-c-s-check-loaded,data-gr-ext-installed
📎 Reference https://stackoverflow.com/questions/45690202/how-to-have-yarn-not-issue-a-warning-for-the-license-field
검색해서 stack overflow 에 나와있는 대로
suppressHydrationWarning={true}를 body태그에 추가하니까 실행이 된다.
//layout.tsx
...
<body suppressHydrationWarning={true}>{children}</body>