npx create-next-app@latest nextjs-dashboard --use-npm --example "https://github.com/vercel/next-learn/tree/main/dashboard/starter-example"
/app
: routes, components, 앱의 로직 등 포함. 대부분의 시간을 여기서 보낼 것/app/lib
: 재사용 가능한 함수들 - 유틸성 함수, 데이터 fetching 함수 등/app/ui
: UI components - 카드, 테이블, 폼 등등/public
: 이미지와 같은 정적 파일들/scripts
: 차후에 db를 만들 때 사용할 스크립트npm run dev
/app/ui
폴더 내부의 global.css
파일에서 모든 routes에 적용될 CSS 규칙 - CSS reset, 링크스타일 등을 정의
어느 컴포넌트에서도 import 하여 사용할 수 있지만, 최상위 컴포넌트에서 적용하는 것이 좋은 관습이다. Next.js에서는 이를 root layout
이라한다.
/app/layout.tsx
에서 import 하여 글로벌 스타일을 적용하자.
클래스명을 통해 스타일링을 하는 Tailwind 프레임워크를 사용할 것을 권장하고 있다. create-next-app
을 이용해 프로젝트를 셋업할 때 Tailwind를 사용할 것인지 묻는데, 이때 yes
를 선택하면 자동으로 필요한 패키지와 설정을 완료해준다.
일전에 Tailwind를 사용해본 경험이 있고, 빠른 개발 프로세스라는 장점에 정말 좋게 생각하고 있던 프레임워크여서 굉장히 반가웠다.
Tailwind의 공식문서도 굉장히 친절하게 설명하고 있고, 원하는 스타일의 클래스명도 검색을 통해 쉽게 찾을 수 있다.
clsx
library to toggle class names조건적으로 클래스명을 주기 위해 clsx
라이브러리를 사용할 것을 추천하고 있다.
import clsx from 'clsx';
export default function InvoiceStatus({ status }: { status: string }) {
return (
<span
className={clsx(
'inline-flex items-center rounded-full px-2 py-1 text-sm',
{
'bg-gray-100 text-gray-500': status === 'pending',
'bg-green-500 text-white': status === 'paid',
},
)}
>
// ...
)}
이런식으로 클래스명에 clsx({”class-name” : boolean})
와 같이 사용하여 조건부 클래스명을 전달할 수 있다.
폰트는 웹 디자인에서 큰 역할을 담당하지만, 커스텀 폰트를 이용하는 것은 폰트를 fetch
하고 load
하는 과정이 필요하다면 퍼포먼스에 영향을 줄 수도 있다.
폰트가 로드되면서 텍스트 크기, 여백, 레이아웃 등에 영향을 미칠 수 있고, 이는 나쁜 사용자 경험을 가져올 수 있다. 이러한 사용자 경험 퍼포먼스를 측정하는 [Cumulative Layout Shift](https://web.dev/articles/cls?hl=ko)
라는 구글에서 사용되는 척도도 있다.
Next.js는 next/font
모듈을 이용하면 자동으로 폰트를 최적화 해준다. 폰트파일을 빌드 타임에 다운로드 받고 정적파일들과 함께 호스팅 해주는데, 이를 통해 사용자가 어플리케이션에 접근했을 때 추가적인 폰트 요청을 하지 않아도 되게 함으로써 사용자 경험 퍼포먼스 문제를 해결한다.
import { Inter } from 'next/font/google';
export const inter = Inter({ subsets: ['latin'] });
fonts.ts
파일에서 폰트를 정의해주고,
import '@/app/ui/global.css';
import { inter } from '@/app/ui/fonts';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={`${inter.className} antialiased`}>{children}</body>
</html>
);
}
원하는 곳에서 위처럼 사용하면 된다.
일반적인 HTML의 img
태그를 사용하면 다음을 수동적으로 처리해주어야한다.
이러한 이미지 최적화를 하나하나 구현하는 대신, next/image
컴포넌트를 활용하면 쉽게 처리할 수 있다.
<Image>
component<Image>
컴포넌트는 HTML의 img
태그를 확장한 것으로, 상기한 이미지 최적화를 자동으로 처리해준다.
import Image from 'next/image';
...
<Image
src="/hero-desktop.png"
width={1000}
height={760}
className="hidden md:block"
alt="Screenshots of the dashboard project showing desktop version"
/>
<Image
src="/hero-mobile.png"
width={560}
height={620}
className="block md:hidden"
alt="Screenshots of the dashboard project showing mobile version"
/>
...
위와 같이 사용하면 된다. md:block
클래스명은 다음과 같은 CSS 효과를 준다.
@media (min-width: 768px) {
.md\:block {
display: block;
}
}
이를 활용해 hidden md:block
과 block md:hidden
클래스명을 통해 데스크탑과 모바일에서의 조건을 걸어줄 수 있다.