[CSS] Vanila-extract


1. ์Šคํƒ€์ผ๋ง ์ข…๋ฅ˜

  1. CSS-in-CSS(tailwind,scss...) - ๊ฐœ๋ณ„ ์Šคํƒ€์ผ ๋‹จ์œ„์˜ stylesheet
  • ๋ณ„๋„์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ „ํ™˜์ด ํ•„์š”์—†์–ด์„œ ์†๋„๊ฐ€ ๋น ๋ฆ„
  • ํด๋ž˜์Šค๋“ค์€ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์Šคํƒ€์ผ๋งํ•  ๋•Œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ๋ชจ๋“ˆ์„ฑ์ด ์ข‹์ง€ ์•Š๋‹ค
  • ๋„ˆ๋ฌด ๋งŽ์€ ์Šคํƒ€์ผ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์Šคํƒ€์ผ ํด๋ž˜์Šค๊ฐ€ ํ˜ผ์šฉ๋˜๋ฉด ์˜คํƒ€๋ฅผ ํ•„ํ„ฐ๋งํ•˜๊ธฐ ๊นŒ๋‹ค๋กญ๋‹ค
  1. CSS-in-JS(styled-components, emotionโ€ฆ) - ์ปดํฌ๋„ŒํŠธ ๋ณ„ ์Šคํƒ€์ผ ๋‹จ์œ„์˜ stylesheet
  • ์Šคํƒ€์ผ๋ง์„ JavaScript ๋‚ด์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์กฐ๊ฑด๋ถ€ ์Šคํƒ€์ผ๋ง์ด๋‚˜ ๋™์  ์Šคํƒ€์ผ ๋ณ€๊ฒฝ์ด ์‰ฝ๋‹ค
  • ์บก์Šํ™”ํ•˜์—ฌ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ๋†’๋‹ค
  • CSS-in-CSS์— ๋น„ํ•ด ๋Š๋ฆผ (์˜ˆ์‹œ๋กœ ํƒ€์ž…์ถ”๋ก ์„ ์œ„ํ•ด ์ถ”๊ฐ€์ ์œผ๋กœ ํƒ€์ž… ์ •์˜๋ฅผ ํ•ด์ค˜์•ผํ•œ๋‹ค, d.ts ํŒŒ์ผ์„ ๋ณ„๋„๋กœ ์ž‘์„ฑํ•ด์•ผ๋  ์ผ์ด ์ƒ๊น€ (styled๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๊ฐ•์ œ๋กœ ๋ณ€ํ™˜)
  • ๋ณ„๋„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜๋กœ ๋ฒˆ๋“ค ํฌ๊ธฐ๊ฐ€ ์ฆ๊ฐ€ํ•จ , d.ts์™€ ๊ฐ™์€ ๋ณ„๋„์˜ ํŒŒ์ผ๋„ ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•ด์ง

์š”์•ฝ

  • ๋น ๋ฅธ ์†๋„ , ๋žœ๋”๋ง ์†๋„ , ์ธํ„ฐ๋ ‰ํ‹ฐ๋ธŒํ•œ ํ”„๋กœ์ ํŠธ โ‡’ CSS-in-CSS
  • ๊ฐœ๋ฐœ ํšจ์œจ์„ฑ , ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์˜ ํ”„๋กœ์ ํŠธ โ‡’ CSS-in-JS

2. Vanila-extract ์ ํ•ฉ

  • CSS-in-CSS - ์ง€๊ธˆ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์˜ ํ”„๋กœ์ ํŠธ ๊ฐœ๋ฐœ์ด ํ•„์š”ํ•˜๋‹ค. tailwind๋Š” ๊ฐ€๋…์„ฑ์ด ๋„ˆ๋ฌด ์•ˆ์ข‹์Œ
  • Styled-components , Emotion js ๋“ฑ - Next13 ๋ฒ„์ „ ์ดํ›„ ๋ถ€ํ„ฐ SSR์—์„œ ํŽ˜์ด์ง€์˜ ์Šคํƒ€์ผ์‹œํŠธ ์ •๋ณด๊ฐ€ ๋กœ๋“œ ์‹œ์ ์— ํฌํ•จ์ด ์•ˆ๋˜์„œ ์Šคํƒ€์ผ ์ ์šฉ์ด ์•ˆ๋˜๋Š” ์ด์Šˆ๊ฐ€ ์žˆ์Œ

    • Next13 ๋ฒ„์ „ ๋ถ€ํ„ฐ app ๋””๋ ‰ํ† ๋ฆฌ์— _app.tsx , _documents.tsx๋ฅผ ์•ˆ์“ฐ๊ธฐ ๋•Œ๋ฌธ์— ์ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•จ
    // _document.tsx
    export default class MyDocument extends Document {
      static async getInitialProps(ctx: DocumentContext) {
        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();
        }
      }
    }
    
    • ๋Œ€์•ˆ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ณ„๋„์˜ ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•จ
    // /app/page.tsx
    import styled from "styled-components";
    
    function HomePage() {
      return <Container>Client Components</Container>;
    }
    export default HomePage;
    const Container = styled.div`
      padding: 0 2rem;
    `;
    
    import React from "react";
    import { ServerStyleSheet, StyleSheetManager } from "styled-components";
    
    export function useStyledComponentsRegistry() {
      const [styledComponentsStyleSheet] = React.useState(
        () => new ServerStyleSheet()
      );
    
      const styledComponentsFlushEffect = () => {
        const styles = styledComponentsStyleSheet.getStyleElement();
        styledComponentsStyleSheet.instance.clearTag();
        return <>{styles}</>;
      };
    
      const StyledComponentsRegistry = ({
        children,
      }: {
        children: React.ReactNode;
      }) => (
        <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
          {children as React.ReactElement}
        </StyleSheetManager>
      );
    
      return [StyledComponentsRegistry, styledComponentsFlushEffect] as const;
    }
    

(1) Vanila-extract ์žฅ์ 

  • ์ฒซ๋ฒˆ์งธ๋กœ CSS-in-TS
  • All the styling APIs in Vanilla Extract take a style object as input.
    • style object ์‚ฌ์šฉ
  • Zero-runtime in TypeScript
    • TypeScript์—์„œ ์Šคํƒ€์ผ์‹œํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•  ๋•Œ, ๋Ÿฐํƒ€์ž„์— ์ถ”๊ฐ€์ ์ธ ์ฒ˜๋ฆฌ๋‚˜ ๊ณ„์‚ฐ ์—†์ด ์ž‘๋™
    • styles.css.ts๋‚˜ .css.ts์™€ ๊ฐ™์€ postfix ํŒŒ์ผ์— ์ž‘์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž‘์„ฑํ•˜๋Š” ๋ชจ๋“  ์Šคํƒ€์ผ์— ๋Œ€ํ•œ ํƒ€์ž… ์ถ”๋ก ์ด ๊ฐ€๋Šฅ
  • Use TypeScript as your preprocessor
    • TypeScript๋ฅผ ์ „์ฒ˜๋ฆฌ๊ธฐ ์ฒ˜๋Ÿผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•จ
  • Zero-runtime in TypeScript
    • TypeScript์—์„œ ์Šคํƒ€์ผ์‹œํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•  ๋•Œ, ๋Ÿฐํƒ€์ž„์— ์ถ”๊ฐ€์ ์ธ ์ฒ˜๋ฆฌ๋‚˜ ๊ณ„์‚ฐ ์—†์ด ์ž‘๋™
    • CSS-in-JS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋Ÿฐํƒ€์ž„์— ์Šคํƒ€์ผ์„ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์ ์šฉํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•จ

(2) Vanila-extract ๊ณง ๋งˆ์ฃผํ•˜๊ฒŒ ๋  ๋‹จ์ 

-์จ๋ณด๋ฉด์„œ ์žฅ๋‹จ์  ์ •๋ฆฌ