이전 포스팅에 프로젝트를 진행하면서 Next.js를 도입하게된 이유에 대해서 설명하였다. Next.js는 서버 사이드 렌더링(SSR)을 지원하여 초기 페이지 로딩 속도를 향상시키고, SEO에 유리한 구조를 제공하는 등 많은 장점을 갖춘 프레임워크이다.하지만, Next.js를 도입하면서 가장 큰 문제는 클라이언트 사이드에서만 동작하는 라이브러리와의 호환성이다. 그 중에서도 CSS-in-JS 라이브러리인 styled-components를 사용하면서 발생한 스타일링 이슈를 이 글에서는 자세히 다루어보자.
기존 프로젝트에서는 React와 styled-components를 이용해 개발했었다. 하지만 Next.js를 도입한 후, 서버 사이드에서 렌더링된 페이지는 스타일이 제대로 적용되지 않는 문제가 발생했다.
Next.js와 styled-components를 함께 사용할 때, 서버 사이드 렌더링과 클라이언트 사이드 렌더링 간에 스타일 순서 불일치 문제가 발생할 수 있다. 이는 Next.js가 페이지를 서버에서 렌더링할 때 스타일이 제대로 적용되지 않은 채로 HTML을 클라이언트로 전달하기 때문에 발생하는 문제이다.
이 문제를 해결하기 위해서는 Next.js와 styled-components가 서버 사이드 렌더링 시에도 스타일을 제대로 적용할 수 있도록 설정을 조정해야 한다._document.js 파일을 수정하여, 서버에서 페이지를 렌더링할 때 styled-components의 스타일을 수집하도록 하였다.
// pages/_document.js
import Document from 'next/document';
import { ServerStyleSheet } from 'styled-components'; // styled-components 패키지에서 제공하는 도구로, 서버에서 스타일을 수집
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />
}),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
}
}
먼저 ServerStyleSheet를 생성한다. 이것은 styled-components가 서버 사이드에서 스타일을 수집하기 위해 제공하는 클래스이다.
원래의 renderPage 함수를 저장하고, 새로운 renderPage 함수를 제공한다. 이 새로운 함수는 App 컴포넌트를 렌더링하면서 그 안에 있는 모든 styled-components 스타일을 수집한다.
원래의 getInitialProps 함수를 호출하여 기본 문서 속성을 가져온다.
getStyleElement 메소드를 이용해서 수집된 스타일을 HTML 스타일 태그로 변환한다.
이 스타일 태그와 기본 문서 속성을 합친 새로운 문서 속성을 반환한다. 이 반환된 속성은 최종적으로 클라이언트에 전송될 HTML 문서에 적용된다.
마지막으로 seal 메소드를 호출해서 더 이상 스타일을 수집하지 않도록 한다.
이렇게 설정하면, 서버에서 페이지를 렌더링할 때 styled-components의 스타일을 수집하여 초기 HTML과 함께 전달한다. 이를 통해 서버 사이드 렌더링에서도 styled-components의 스타일이 제대로 적용되도록 할 수 있다.
또한, 이 문제를 해결하기 위해 .babelrc 파일에 styled-components 플러그인을 추가한다.
// .babelrc
{
"presets": ["next/babel"],
"plugins": [["styled-components", { "ssr": true }]]
}
이렇게 설정하면, Next.js와 styled-components를 함께 사용하여도 서버 사이드 렌더링 시에 스타일이 제대로 적용된다.