Nextjs15에서 css-in-js을 써보자

MM·2025년 3월 27일
post-thumbnail

no more tailwind

테일윈드는 확실히 익숙해지니 와다다 치기 편하긴 했지만, 아래와 같은 사항의 경우 오히려 불편했다.

  • 디자이너의 요구사항이 세부적
  • 명확한 디자인패턴 부재
  • vw기반의 반응형 디자인
  • 특정 값에 따른 속성값 분기처리 <특히 이거.. 체감상 그냥 인라인 style이었음..

이번엔 동적인 스타일 변화가 많은 페이지라, 그냥 css-in-js를 쓰기로 했다.

왜 emotion인가?

2년 전 쯤의 사이드프로젝트에서...

nextjs12에 styled component를 쓸 때 하이드레이션 에러로 꽤나 고생했던 기억이 있다.
styled component는 사용이 간편하지만 런타임 시 스타일을 동적으로 생성하기 때문에 서버와 클라이언트의 상태가 같지 않으면 하이드레이션 에러가 곧잘 나타났었다.

당시의 삽질

styled component 공식 문서에서 제공한 대로, ssr에서 렌더링시마다 클라이언트에서 스타일을 캡쳐해 서버용 스타일시트를 만들어 contextApi로 전달하는 방법을 사용했는데...

스타일 동적 생성의 문제점

스타일 동적 생성의 문제점으로는 하이드레이션 에러 뿐만 아니라, style 태그를 head에 삽입할 때 메모리와 성능에 부담을 주는 부분도 있었다.
특히 ssr에서 사용하기 위해 서버 스타일 시트를 매번 생성한다면 더..!
이번 프로젝트에서는 첫 페이지 로딩 속도와 성능을 가능한 끌어올리는 것이 목표였기 때문에!
성능 최적화에 중점을 둔 emotion을 선택하기로 했다.

SSR에서 emotion 사용하기

서버에서 렌더링된 스타일을 추출해다 클라이언트에 적용
-> style component하고 주입방향이 반대네..?
-> 근데 개인적으로도 이게 맞다고 본다. 어차피 초기상태는 서버에서 내려줘야 하니..

app router에서 emotion을 사용할 수 없다..

며칠동안 계속 구글링하고 chatgpt와 씨름하며 캐시 주입방법을 찾았지만, 진행하면 진행할수록 이건 뭔가 아니라는 생각만이 더 들었다...

왜 나는 css를 파싱해서 헤더에 꾸역꾸역 넣고 앉아있는가...

그래서 결국 아직도 앱라우터에 대한 지원이 없는 emotion을 포기하고, pandas css를 사용해보기로 했다.

왜 pandas css인가?

믿음직스럽다, panda css!

기존 css-in-js의 ssr 해결 방법

  1. 서버에서 HTML을 생성할 때 style을 모아다 head에 넣어줌
    • 기존 CSS-in-JS는 서버 렌더링 중 스타일을 모아서 문자열로 변환..
  2. 클라이언트가 HTML을 로드시 head에 포함된 CSS가 즉시 적용됨
  3. Hydration 이후 JS가 실행되며 추가적인 css를 head에 동적 삽압

단점

  • 서버 렌더링시 문자열 변환 시간 필요
  • FOUC(Flash of Unstyled Content)로 JS가 실행되기 전까지 스타일 안 보임
  • hydration 에러

panda css의 ssr 해결 방법

  1. 정적 CSS를 생성하는 데 필요한 데이터를 객체 기반 함수로 변환
  2. PostCSS 플러그인을 사용해 위 함수로 정적 atmoic CSS 파일을 만듦
  3. 정적 css이므로 JS 실행 없이도 스타일을 적용할 있음!

장점

  • 정적 css라 클라이언트, 서버 둘 다 동일한 스타일 적용!
    • css-in-js지만 서버컴포넌트에서도 사용가능!
  • 모든 과정이 빌드 시점에서 끝나므로 런타임 성능에는 영향 없음
    • = Zero-runtime CSS-in-JS

postcss란?

플러그인 기반 CSS 처리기 라이브러리!
여러 플러그인을 사용하여 css파일 크기를 줄이거나 자동 브라우저 최적화를 해주는 등 바닐라 css를 쓸 때보다 더 편리하게 사용할 수 있다.

atomic css란?

각각의 CSS 클래스가 하나의 스타일 속성만 가지는 것. 성능과 가독성에 최적화!
-> 테일윈드 같은 거!



emotion 트러블슈팅

The edge runtime does not support Node.js 'stream' module

edge runtime

nextjs middleware에서는 edge runtime을 사용한다! (페이지는 node runtime)

  • 서버리스 : 요청이 들어오면 서버가 클라우드 엣지에서 자동할당, 동적 생성
    • 요청에 대한 반응 속도가 매우 빠르다!!
  • 엣지 컴퓨팅: 사용자의 위치에 가까운 서버에서 실행
    • 경량화를 위해 Node.js 모듈(예: stream, fs, path)을 지원하지 않음..???
    • 하긴 미들웨어에서 저런 작업을 하진 않지..

node runtime socket VS edge runtime fetch

일단 결론적으로.. 실시간 양방향 데이터 전송에는 소켓, 빠른 요청 응답과 지리적으로 분산된 서버에서의 저지연 통신은 Edge 런타임의 fetch가 더 유리하다고 하는데..
우리 프로젝트인 주식 대시보드에서 필요한 건 후자긴 하다.


..하지만 나는 소켓통신을 하고 싶어서 이 프로젝트를 진행한 건데...!!!!!
대가리가 아파온다
백엔드분하고 상의해보자....
-> edge런타임으로 가기로 했다! 단방향 통신에 굳이 소켓을 만들 필요가 없다는 결론.



Panda css 트러블슈팅

panda css 적용 안 되는 문제

공식문서를 그대로 진행하면 안 됨..

panda.config.ts에서 아래처럼 수정해야 하는 부분이 있는데, app라우터의 경우 src까지 빼줘야 한다.

//이게 아니라
include: ["./src/components/**/*.{ts,tsx,js,jsx}", "./src/app/**/*.{ts,tsx,js,jsx}"],
  
//이걸 넣어줘야 됨..
include: ["./components/**/*.{ts,tsx,js,jsx}", "./app/**/*.{ts,tsx,js,jsx}"],

안 되어서 chatgpt stackoverflow 공식깃허브 뒤져가며 별 세팅값을 다 넣다 이렇게까지 세팅이 복잡하지 않을 것 같다는 촉이 훅 와서.. 디렉토리를 확인해 봤는데 역시나.
공식문서 맹신자인 나로써는 이럴 때마다 정신이 아득해진다 😂

profile
중요한 건 꺾여도 그냥 하는 마음

0개의 댓글