TIL - Next.js App 전역 스타일링 (feat. styled-components 오류)

신혜린·2024년 3월 30일
0

TIL

목록 보기
19/19
post-thumbnail

Nextjs를 사용한 프로젝트를 생성 중, 아이폰 15 프로 크기에 맞춰 개발하기 위한 전역 스타일링 설정이 필요해서 찾아보다가 정리하는 글 (📁 styles > globals.css)

Next.js 12 이상에서 app 폴더를 사용할 경우, app 폴더 내 _app.js 파일을 생성하여 전체 애플리케이션에 대한 커스텀 App 컴포넌트를 정의한다는 사실을 알게 되었다.

폴더 및 파일 구조

폴더 및 파일의 전체적인 구조는 다음과 같다.

my-nextjs-project/
├─ app/
│  ├─ _app.js
│  ├─ (다른 컴포넌트 및 페이지)
├─ styles/
│  ├─ globals.css
├─ public/
│  ├─ ...

_app.js 파일 생성

app 폴더의 루트에 _app.js 파일을 생성 후에는 다음과 같이 정의 해준다.

// app/_app.js

import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
    return <Component {...pageProps} />;
}

export default MyApp;

MyApp 함수 정의

여기서 MyApp 함수는 두 가지 주요 목적을 갖는다.

1️⃣ 페이지 초기화: 모든 페이지 요청에 대해 실행되며, 페이지 컴포넌트와 페이지 프로퍼티(`pageProps`)를 렌더링한다.
2️⃣ 전역 상태 및 스타일 관리: 전역 CSS, 상태 관리 등을 설정하여 애플리케이션의 모든 페이지에 적용한다.
  • Component : 현재 라우트에 해당하는 페이지 컴포넌트로, 페이지의 주요 내용을 구성한다.
  • pageProps : 서버 사이드 렌더링이나 정적 생성을 통해 미리 가져온 페이지의 props로, 이를 통해 각 페이지는 필요한 데이터를 사전에 로드하여 렌더링할 수 있다.

또한 _app.js 에서 이 두 prop를 사용하여 모든 페이지에 공통적으로 적용되어야 하는 레이아웃, 스타일, 상태 관리 등을 처리할 수 있다.
예를 들어, 모든 페이지에 공통적인 헤더나 푸터, 사이드바를 추가하거나 전역 상태 관리 라이브러리를 연결할 수 있다.

// 헤더와 푸더 추가 예시
// _app.js

function MyApp({ Component, pageProps }) {
  return (
    <>
    	<Header /> {/* 모든 페이지에 공통 헤더 */}
    	<Component {...pageProps} /> {/* 현재 페이지 컴포넌트와 그 props를 렌더링 */}
		<Footer /> {/* 모든 페이지에 공통 푸터 */}
	</>
	);
}

export default MyApp;



(추가) 서버 사이드 렌더링(SSR) styled-components 적용

Next.js 프로젝트 내 CSS 대신 styled-components를 적용시키려고 했더니, 서버 사이드 렌더링을 위해 추가로 설정해야하는 것들이 있어서 정리한다.

1. babel-plugin-styled-components 설치

yarn add babel-plugin-styled-components

2. 프로젝트 루트에 .babelrc 파일 추가

{
  "presets": ["next/babel"],
    "plugins": [["styled-components", { "ssr": true, "displayName": true }]]
}

3. 전역 스타일 정의

styles 디렉토리 내 GlobalStyle.js 파일 생성

// styles/GlobalStyle.js

import { createGloablStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

  /* iPhone 15 Pro의 화면 크기에 맞는 스타일 */
  @media only screen and (min-device-width: 390px) and (max-device-width: 844px) {
    body {
      width: 390px;
      margin: 0 auto;
    }
  }
`;

export default GlobalStyle;
  • 모든 화면에 기본적인 스타일 적용
  • @media 미디어 쿼리를 사용하여 iPhone 15 Pro 의 화면 크기에 맞는 조건에서만 특정 스타일을 적용 (width: 390px; margin: 0 auto;)
  • 해상도는 390px X 844px 로 설정

4. 전역 스타일 적용

_app.js 파일에서 GlobalStyle 컴포넌트 임포트하고 애플리케이션의 최상위에 적용하기

// pages/_app.js 또는 app/_app.js

import GlobalStyle from '../styles/GlobalStyle';

function MyApp({ Component, pageProps }) {
  return (
    <>
    	<GlobalStyle />
    	<Component {...pageProps} />
	</>
	);
}

export default MyApp;


서버와 클라이언트


위와 같이 설정해주고 난 뒤 서버를 켜보니 이런 오류가 떴다.
찾아보니, nextjs는 13 버전 이후로 서버클라이언트 컴포넌트가 각각 구분되기 때문에 발생하는 오류인 것으로 나타났다.

즉, Next.js 13 이상에서 styled-components 를 사용하려고 했더니 클라이언트 사이드에서만 처리되어야 하는 styled-components가 서버 사이드에서 실행되었기 때문에 발생한 오류인 것이다.

use client

파일 내에 use client 지시어를 사용하면 컴포넌트를 클라이언트 컴포넌트로 명시적으로 변환해주기 때문에 컴포넌트 파일의 최상단에 추가해주면 오류가 해결된다.

하지만 그럼 컴포넌트 파일이 전부 클라이언트 컴포넌트로 변환되기 때문에 의도와는 다르게 설정이 된다는 문제가 발생한다.

그래서 styled 파일을 별도로 추가해서 style 파일에만 use client 지시어를 적용시키기로 했다.

  • style 파일 분리 후(ex. login.style.js) use client 지시어 사용
  • component(ex.page.js) 파일에서 style 파일 임포트
// login.style.js

"use client";

import styled from 'styled-components';

export const LoginContainer = styled.div`
	border: 1px solid black;
`;

export const LoginBox = styled.div`
	border: 1px solid blue;
`;
// page.js

import * as S from "./login.style";

export default function Login() {
    return (
        <S.LoginContainer>
            <S.LoginBox>Another content</S.LoginBox>
        </S.LoginContainer>
    );
}
profile
개 발자국 🐾

0개의 댓글