10/17 TID: 바닐라 익스트랙트로 마이그레이션하기

그른손·2023년 10월 17일
0

겪은 문제들

테일윈드와 바닐라 익스트랙트를 동시에 사용할 수 없음

원래 계획은 테일윈드가 적용된 상태에서 바닐라 익스트랙트를 동시 설치하고, 테일위드로 스타일링된 컴포넌트들을 하나하나 바닐라 익스트랙트로 바꾸는 식으로 점진적 적용을 하는 거였는데, 아래와 같은 오류가 발생했습니다!

추측하기로는 테일윈드와 바닐라 익스트랙트를 동시에 적용하면서 발생하는 충돌 같은데, 검색을 해 봐도 사례가 별로 없더라구요. (그리고 자꾸 제빵 레시피가 나와요!) 커리어리에서 비슷한 문제 (테일윈드와 스타일드 컴포넌트 동시 적용)를 찾았는데, 해당 질문의 답변에도 '설정을 잘 만져주면 된다'라고만 되어 있어서...🥲 이런 문제도 해결해봐야 경험이 될텐데! 이리저리 찾아보고, 바닐라 익스트랙트 초기 설정도 바꿔봤지만, 아무래도 테일윈드랑 같이 적용하는 게 드문 경우다 보니 관련 자료도 없고 해서 일단 테일윈드를 삭제했습니다...
모르겠다고 때려치우는 경험만 늘어나는 것 같아서 슬프네요

prop을 받거나 상태를 활용할 수 없음

제 포트폴리오에는 다크 모드와 색상 테마를 리덕스로 구현해서 적용하고 있는데요! 이를 적용할 때에는 아래와 같이 이용합니다.

const currentColorScheme = useColorScheme();
const darkMode = useDarkMode();

<div style={{
	background: darkMode ? 
		currentColorScheme.DARK.BG :
		currentColorScheme.LIGHT.BG,
    color: darkMode ?
    	currentColorScheme.DARK.TEXT :
        currentColorScheme.LIGHT.TEXT

}}>숭구리당당</div>

그러나! 바닐라 익스트랙트는 빌드타임에서 css를 처리합니다! 이게 무슨 말이냐! css.ts 파일에 스타일을 정의해두면, 바닐라 익스트랙트는 이를 실제 css 파일로 추출합니다! 번들에 스타일이 포함되는게 아니라 별도로 처리되는 것이지요!
emotion이나 styled-components같은 CSS-in-Js 라이브러리는 런타임에서 스타일링을 생성하고 적용합니다! 아래와 같이 동적인 스타일 변경, 조절이 가능하구요!

const Button = styled.button`
  background-color: ${props => props.primary ? 'blue' : 'gray'};
`;

하지만, 바닐라 익스트랙트는 빌드 타임에서 css를 처리하기 때문에, 런타임에 존재하는 자바스크립트 코드와 상호작용할 수 없습니다! 조건부 스타일링같은 경우에도 프롭을 직접 넘겨줄 수 없으므로, 스타일링을 적용하는 단에서 조건부로 적용을 시켜줘야 합니다! 뭔소리냐면,

//style.css.ts

const defaultStyle = style({
	color: 'blue',
    }
    
const conditionalStyle = style({
	color: 'red',
    });

//Component.tsx

function Component() {
  const [isSpecial, setSpecial] = useState(false);

  return (
    <div className={`${defaultStyle} ${isSpecial && conditionalStyle}`}>
      숭구리당당
    </div>
  );
}

이런 식으로! 적용할 수 있습니다. 그 외에도 변수와 테마를 활용한 스타일링(createVar, createTheme등 사용)을 통해 비슷한 결과를 얻을 수 있습니다.

const vars = createTheme({
  colors: {
    primary: 'blue',
    secondary: 'gray'
  }
});

const buttonStyles = style({
  backgroundColor: vars.colors.primary
});

다만, 이 경우에도 스타일을 적용하는 건 css.ts 파일 내에서 어느 부분에 어떤 스타일을 적용할지 미리 정해져 있어야 하기 때문에 제가 현재 사용하고 있는 컬러스킴과는 맞지 않는 면이 있습니다!

  HARBOR: {
    TITLE: "Harbor",
    DARK: {
      BG: "#4F4F5C",
      TEXT: "#EEF1F2",
      PRIMARY: "#F2B5B5",
      SECONDARY: "#6CC1C1",
      ACCENT: "#F9D988",
    },
    LIGHT: {
      BG: "#e6f3f3",
      TEXT: "#4f4f5c",
      PRIMARY: "#F2B6B6",
      SECONDARY: "#3E9393",
      ACCENT: "#F9D988",
    },
  }

제가 정의한 컬러스킴은 이런 구조를 가지고 있습니다. 이 중에서 BG는 background, TEXT는 color에 적용하기로 정해져 있지만, 그 외 색상 (PRIMARY, SECONDARY, ACCENT)은 사용처가 명확하게 정해져있지 않습니다! 버튼 배경색 등으로 쓰거나, 호버 시에 ACCENT 색깔을 보여주거나 제 멋대로 쓰고 있거든요!
그래서 이걸 그대로 사용하려면, defaultStyle(BG와 TEXT 적용), primaryStyle(background에 PRIMARY 적용), secondaryStyle(background에 SECONDARY 적용) ... 등으로 하나하나 프리셋을 만들어놔야 하겠죠? 근데 그러기가 싫어서 이렇게 했습니다!

interface BackgroundProps {
  children: ReactNode;
}

export default function Background({ children }: BackgroundProps) {
  const darkMode = useDarkMode();
  const colorScheme = useColorScheme();
  return (
    <div
      style={{
        color: darkMode ? colorScheme.DARK.TEXT : colorScheme.LIGHT.TEXT,
        background: darkMode ? colorScheme.DARK.BG : colorScheme.LIGHT.BG,
        width: "100vw",
        height: "100vh",
      }}
    >
      {children}
    </div>
  );
}

이런 식으로, 컬러스킴을 사용하는 경우에만 바닐라 익스트랙트 스타일링 대신 인라인 스타일을 적용하기로 했고, Background라는 별도의 컴포넌트를 만들어서, 컬러스킴이 쓰이는 가장 큰 용도인 'BG와 TEXT 컬러 적용' 로직을 분리해서 갖고있게끔 만들었습니다! 이게 최선의 해결책은 아닌 것 같고, 분명히 더 현명한 방법이 있을 것 같지만... 바닐라 익스트랙트를 좀 더 써보고, 개선할 방법을 알게 되면 적용해볼 생각입니다

반응형 디자인의 적용

테일윈드에서는 반응형을 각 태그에 sm: md: 이런 식으로 짜잘짜잘하게 적용해야 해서 불편했는데요! (md 화면크기에 적용해야 할 스타일이 여러개면, md:bg-gray-500 md:font-bold md:rounded-sm 이런 식으로 하나하나 써줘야 했음) 바닐라 익스트랙트에서는 아래와 같이 적용이 가능합니다

//mediaQueries.ts
export const mediaQueries = {
  SCREEN_SM: "screen and (min-width: 640px)",
  SCREEN_MD: "screen and (min-width: 768px)",
  SCREEN_LG: "screen and (min-width: 1024px)",
  SCREEN_XL: "screen and (min-width: 1280px)",
  SCREEN_2XL: "screen and (min-width: 1530px)",
  SCREEN_3XL: "screen and (min-width: 1536px)",
  SCREEN_4XL: "screen and (min-width: 1850px)",
  SCREEN_5XL: "screen and (min-width: 2000px)",
  SCREEN_6XL: "screen and (min-width: 2300px)",
};

//style.css.ts
 const title = style({
    fontSize: "60px",
    position: "relative",
    ":hover": {
      filter: "invert(1)",
    },
    "@media": {
      [mediaQueries.SCREEN_SM]: {
        fontSize: "80px",
      },
      [mediaQueries.SCREEN_MD]: {
        fontSize: "90px",
      },
      [mediaQueries.SCREEN_LG]: {
        fontSize: "100px",
      },
    },
  })

좀 무식한 방법인 것 같지만😅 일단은 적용된 스타일을 그대로 옮기기부터 하려구요

테일윈드 => 바닐라 익스트랙트 스타일 변환의 피곤함

지난 글에서 썼던, '테일윈드는 키워드가 제멋대로야!'에서 오는 문제입니다. 테일윈드 쓸 때는 그냥 있는 유틸리티 클래스 마음대로 불러와서 뚝딱뚝딱 적용하니까 좋았는데, 스타일 코드를 직접 작성해야 하는 css 라이브러리로 마이그레이션을 해야 하는 상황이 오니, 지금까지 썼던 테일윈드 유틸리티 클래스가 css로 옮기면 어떻게 되는지 일일히 테일윈드 문서를 뒤져봐야 하는 상황이 왔습니다... text-xs는 font-size로 몇인지? rounded-sm은 border-radius로 몇인지? 이런거 하나하나 다 찾아보면서 해야한다고 생각하니 정신이 아득해졌는데요, 하지만!! 제가 겪는 문제는 이미 수많은 사람들이 밟고 지나간 길!! 저처럼 귀찮은 거 싫어하는 사람이 만들어놓은 멋진 툴로 문제를 해결할 수 있었습니다! https://tailwind-to-css.vercel.app/

생각한거

  • 2번 문제에서 다룬 상황 (컬러스킴 관련)을 좀 더 깔끔하게 해결할 수 있는 패턴을 고려해봐야겠다
  • 지금은 단순히 테일윈드 코드를 바닐라 익스트랙트로 옮기고 있을 뿐인데, 이렇게 되면 불필요한 중복 스타일 코드가 많이 생길 것 같다.
  • css-in-js에서 바닐라 익스트랙트로 마이그레이션했으면 성능 차이도 경험해볼 수 있었을 것 같다!
profile
프론트엔드 개발자

1개의 댓글

comment-user-thumbnail
2024년 1월 24일

recipe쓰면 아주 편하게 조건부 스타일링 처리 가능합니다. 그 것 말고도 sprinkles도 있구요.

답글 달기