caias / monorepo-temp

yarn berry monorepo poc
0 stars 0 forks source link

next14에서 css-in-js 고찰 #2

Open caias opened 6 months ago

caias commented 6 months ago

css-in-js중 js로 컴파일 되는 애들은 무조건 client component를 쓸수 밖에 없다.

물론 서버사이드 랜더링을 사용하는데에는 지장이 없다. 하지만 next14에서 추구하는 방향에 맞는지는 모르겠다. 리액트의 핵심인 hook을 사용하는 컴포넌트와 onClick, onChange같은 이벤트 핸들링을 사용하는곳은 무조건 client component로 쓸수밖에 없는데 정적인 DOM으로 이루어진 컴포넌트까지 굳이 Css-in-js를 써가면서 클라이언트 컴포넌트로 만들어야 될까 심히 고민된다.

styled-compoent registry 방법 (next.js 공식 문서 발췌)

이미 useclient 박고 시작한다.

'use client';

import { useState, PropsWithChildren } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';

export default function StyledComponentsRegistry({
  children,
}: PropsWithChildren) {
  const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());

  useServerInsertedHTML(() => {
    const styles = styledComponentsStyleSheet.getStyleElement();
    styledComponentsStyleSheet.instance.clearTag();
    return <>{styles}</>;
  });

  if (typeof window !== 'undefined') return <>{children}</>;

  return (
    <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
      {children}
    </StyleSheetManager>
  );
}

기존에 쓰던 styled-component globalStyle

createGlobalStyle 함수때문에 'use client'박아야됨

'use client';
const GlobalStyle = createGlobalStyle`
  ${ResetStyle}
  ${globalStyle}
`;

임시 테스트용 Client component

styled-component로 만든 text ui component 역시 'use client'빼면 에러남

'use client';

import { Text } from '@libs/ui';

function Client() {
  return <Text>client</Text>;
}

export default Client;

임시 테스트용 server component 및 Wrapper component

import { PropsWithChildren } from 'react';

function Wrapper({ children }: PropsWithChildren) {
  return <>{children}</>;
}

export default Wrapper;

function Server() {
  return <div>server</div>;
}

export default Server;

App router root Page

import Wrapper from '@components/Wrapper';
import Server from '@components/Server';
import Client from '@components/Client';
import Registry from '@components/Registry';
import GlobalStyle from '@components/GlobalStyle';

export default function Home() {
  return (
    <>
      <GlobalStyle />
      <Registry>
        <Wrapper>
          <Server />
          <Client />
        </Wrapper>
      </Registry>
    </>
  );
}

해당 page를 빌드 하게 되면 아래와 같은 결과를 볼수 있다. image

RSC( react server component)는 기존의 SSR이랑은 분명 다르다. 기존에는 서버사이드 랜더링을 하게되면 서버에서 html을 내려주지만 RSC는 서버에서 이미 실행후에 직렬화된 JSON 스트림으로 전달되기때문에 어떠한 bundle에도 포함될 필요가 없다.

기존의 next의 SSR은 초기 로딩속도에만 이점이 있을 뿐, 번들사이즈는 CSR이랑 거의 별차이가 없다. next14로 마이그레이션 하게되면 이걸 제일 많이 살려야지 마이그레이션 하는 의미가 있을거 같은데.. 어렵네잉

갑자기 궁굼해진다. RSC컴포넌트들은 루트 최상단에서 스테이트가 변경되도 re-rendering에 영향을 받는지 추후에 테스트 해봐야겠다. 왠지 re-rendering 안될거같은 느낌인데..

branch: issue/css-in-js dir: ./apps/next-latest

hanseungyoo commented 6 months ago

개중 대안으로 찾아본게 vanilla-extract (https://vanilla-extract.style/) 랑 panda css (https://panda-css.com/) 두개를 좀 보고 있는 중입니다.

실제로 vanilla extract는 css로 번들되다 보니 use client를 사용하지 않아도 되어서 낫더군영

그리고 RCC와 RSC도 약간 저는 좀 심하게 생각해보게 되었는데요, 완전히 관점이 달라지긴 했어요 기존처럼 html string template을 그리고, 나머지 전체 번들링을 해주지 않는 구조에서 생각을 해보니, 실제로 컴포넌트 구성에 관련해서도 관점이 많이 달라지긴 했습니당

caias commented 6 months ago

맞습니다.. 뭔가 작동방식에 대해서 기존과는 완전히 다르게 발상의 전환이 필요할거 같네요. css는 개인적으로는 작동방식이 이렇게 된 이상 그냥 정적파일이나 module.scss (css X) 쓰는게 나아보이긴 합니다. 에픽 브랜치 들어가보니 컴포넌트 자체는 RSC취급하지만 vanila-extract 컴파일된 index.css.ts 파일들은 번들에 포함이 되네요.