[개인 프로젝트 ShareLife] SNS 만들기 ShadCN & Tailwind CSS 적용

규갓 God Gyu·2024년 8월 10일
0

프로젝트

목록 보기
62/81

ShadCN + Tailwind CSS

앞서 기획에서 단순하게 사용만하겠다고 했는데 실제로 어떻게 사용해야할지는 찾아봐야한다.

tailwindcss관련 세팅은 next가 알아서 해줘서 딱히 건든건 없었고,

ShadCN 일단 설치

pnpm add shadcn/ui

이 과정에서 ShadCN이 ui관련 컴포넌트라는 사실을 알게 되었고,
바로 사용할 수 없었다.

프로젝트에 특정 컴포넌트를 추가하는 추가 설정이 필요했는데,
shadcn/ui를 설치한다고 바로 사용이 불가했다

그래서 좀 더 알아본 ShadCN/ui는

Radix UI 및 Tailwind CSS를 사용해 구축된 '재사용' 가능한 컴포넌트.
컴포넌트 라이브러리가 아닌 앱에 copy and past하여 재사용 가능한 구성요소 모음
따로 pnpm add 하여 종속성 설치를 하진 않음
그렇다면 내 해석상 tailwind를 검색해서 가져오는 것처럼 이것도 비슷한 느낌이지 않을까 싶은데..?

그리고 tailwindcss와 같이 사용하는 이유는

shadcn가 tailwind css 시스템을 도입하고 있고 호환성이 좋아서이다!

공식문서에서는

이렇게 설치하라고 했는데 나는 pnpm만 사용하므로

pnpm add shadcn-ui@latest init

이렇게 추가하니 앞서 shancn/ui로 설치했을땐 package.json에 저장이 안되었는데 이젠 저장이 되었다.

이후 컴포넌트 제이슨 파일을 만들라는 것 같아서 추가해주었고,

너무 직관적으로 도입해서 에러가 떴다 ㅎㅎㅎ

그래서 gpt 도움을 받아

{
  "useTypeScript": "no",
  "style": "Default",
  "baseColor": "Slate",
  "globalCSS": "app/globals.css",
  "useCSSVariables": "no",
  "tailwindConfig": "tailwind.config.js",
  "importAlias": {
    "components": "@/components",
    "utils": "@/lib/utils"
  },
  "usingReactServerComponents": "no"
}

이런식으로 넣었는데,
나는 typescript를 사용할건데 no? 처음부터 내 프로젝트의 성격상 그냥 무지성으로 도입하는건 좋지 않다 느꼈고,
그냥 공식문서의 3개 정도만 추가시키기로 결정하였다.

{
  "style": "Default",
  "baseColor": "Slate",
  "useCSSVariables": "no"
}

style은 기본 스타일
baseColor 는 Slate - 선택된 색상
useCSSVariables - 색상에 CSS 변수 사용할지? no
여기서 CSS 변수는

:root {
    --primary-color: #3498db; /* 블루 색상 */
    --secondary-color: #2ecc71; /* 그린 색상 */
    --font-size: 16px; /* 기본 글꼴 크기 */
}

이런식으로 어떤 색상을 변수화 시킨다는 의미인데,
하나하나 다 지정해주면 날 샐것같으니 no가 맞는것같다

이후 tailwind와 같이 사용하기 위해
content에 shadCN 컴포넌트 경로 추가

//tailwind.config.ts

import type { Config } from "tailwindcss";

const config: Config = {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
    "./node_modules/shadcn-ui/dist/**/*.{js,ts,jsx,tsx}", // ShadCN 경로 추가
  ],
  theme: {
    extend: {
      backgroundImage: {
        "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
        "gradient-conic":
          "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
      },
    },
  },
  plugins: [],
};
export default config;

그 다음에 글꼴 설정을 해줘야하는데,
layout.tsx의 폰트 설정과 CSS 클래스를 조정하라고 나와있다.

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  );
}

이게 기존 루트레이아웃이였다면

// src/app/layout.tsx
import "@/styles/globals.css";
import { Inter as FontSans } from "next/font/google";
import { cn } from "@/lib/utils"; // `cn` 함수는 클래스 이름을 결합하는 유틸 함수

const fontSans = FontSans({
  subsets: ["latin"],
  variable: "--font-sans",
});

export default function RootLayout({ children }: RootLayoutProps) {
  return (
    <html lang="en" suppressHydrationWarning>
      <head />
      <body
        className={cn(
          "min-h-screen bg-background font-sans antialiased",
          fontSans.variable
        )}
      >
        {children}
      </body>
    </html>
  );
}

이렇게 FontSans와 cn을 변경해서,

  • fontSans.variable - CSS 변수??

오케이 그러면 components.json의
useCSSVariables를 yes로 바꿔서 사용할 수 있도록 바꾸자

근데

이전에 세팅해놓은 alias 때문에 가져오는 방식에 문제가 있었던 것 같다.

근데 그냥 src안에 lib과 utils 파일이 없어서 이것또한 생성해줘야하는 문제인 것 같다... 처음쓰는건 너무 어려워 ㅠㅠ

src/lib/utils.ts 파일 만들어주고

export function cn(...classes: (string | undefined | false)[]) {
  return classes.filter(Boolean).join(' ');
}

이 문구를 넣어주는건 왜 공식문서에서 안알려주는데? ;;

저 내용은 cn함수가 일반적으로 클래스 이름을 조건에 따라 결합해주는 함수

나중에 쓰면서 익숙해지면 될듯

  • ...classes: 여러 개의 클래스 이름 배열로 받음
  • filter(Boolean) : 배열에서 'false','undefined','null'같은 falsy값을 필터링
  • join(' '):필터링된 클래스 이름 공백으로 구분하여 하나의 문자열로 결함

근데 애초에 생각해보면

여기서 YES 즉, 절대경로 사용하려고 customize하려고만했고 세팅을 안해줬기 때문에,

baseUrl - 기본 디렉토리 경로 설정
paths - @/ 경로 별칭을 ./src/로 매핑해서 @/로 시작하는 경로를 src/ 디렉토리 내의 파일로 변환
를 추가해준다.

{
  "compilerOptions": {
    "baseUrl": ".", //추가
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"] //이미추가되어잇넹
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

이제 나는 절대 경로를 사용할 것이기 때문에
src/lib/utils.ts에 export function 을 가져온다치면

import { cn } from "@/lib/utils"; // 절대경로 사용

@ 로 src에 접근해서 바로 뽑아올 수 있다 상대경로 아니여도

이후 제대로 노드모듈스 적용하려고

rm -rf node_modules
pnpm install

지웠다 재설치했는데,
확실히 진짜 빠르다 pnpm install이 ㄷㄷ

근데??

어휴 머가 이리 오류가 많이 뜨냐 ;;

이 부분을 위해서

types에 tailwindcss 추가 해도
에러는 계속되어있음

그래서 말이 안된다 에러가 생길 수 없는 구조다 생각해서
껏다 켰더니 해결 ㅎㅎㅎㅎ 개짜증나네

이제 버튼 한번 컴포넌트 가져와서 사용해봅시다~!

공식문서 참고해서
src/components/ui/button.tsx
에서 저렇게 선언하니까 바로 안되고 있음

type에 대해서 문제가 있는 듯 함

그래서 src/types/shadcn-ui.d.ts에서
해당 코드 선언해주니
이젠 Button이 없다

그래서 공식 홈페이지에서

pnpm add shadcn-ui@latest add button

로 해도 계속 형식 선언을 찾을 수 없다고 떠서

pnpm과 호환성에 문제가 있다고 생각해
어쩔 수 없이 npx로 설치하였다

npx
node.js 패키지를 일회성으로 실행할 수 있게 해주는 도구

약간 yarn, npm, pnpm과 다른 역할로 생각됨
패키지를 글로벌로 설치하지 않고 명령어를 한번만 실행할 때 사용하는 도구

npx shadcn-ui@latest add button

결국 이걸로 해도 에러가 떠서

직접 src/components/ui에 button.tsx
파일 만들어서 선언해줬더니
제대로 button에 대해서 import해졌고,

현재 이런 에러가 뜨고 있음

찾아보니 globals.css가 src 바로 밑에 있지 않고 src/app 안에 있는 파일이라서 에러가 떳었음 그래서
@/app/globals.css 로 import해서 해결!

이젠 해결했더니 이런 에러가 뜸

이건 다행히 client component 에서 버튼을 사용할 수 있는 것이므로


'use client'
클라이언트 컴포넌트로 사용하겠다 라고 해서

겨우 겨우 진짜 겨우 완성...ㅋㅋㅋ;;
언제 해 이래서 ㅋㅋㅋㅋ

이제 대충 shadCN은 사용해보면서 익히고
진짜 진행해보자

profile
웹 개발자 되고 시포용

2개의 댓글

comment-user-thumbnail
2024년 8월 12일

멋있어요~

1개의 답글