Gatsby와 TypeScript로 정적 사이트 생성하기 🚀
안녕하세요, 여러분! 오늘은 웹 개발의 흥미진진한 세계로 여러분을 초대하려고 해요. 특히 Gatsby와 TypeScript를 사용해 정적 사이트를 만드는 방법에 대해 알아볼 거예요. 이 조합은 마치 슈퍼히어로 팀업과 같아요! 🦸♂️🦸♀️ Gatsby는 빠른 속도로, TypeScript는 강력한 타입 체크로 우리의 웹 개발을 한층 더 업그레이드시켜줄 거예요.
여러분, 혹시 재능넷이라는 사이트를 들어보셨나요? 이 사이트는 다양한 재능을 거래하는 플랫폼인데요, 우리가 오늘 배울 내용을 활용하면 이런 멋진 사이트도 만들 수 있답니다! 자, 그럼 이제 본격적으로 시작해볼까요?
🎯 학습 목표:
- Gatsby의 기본 개념 이해하기
- TypeScript의 장점 알아보기
- Gatsby와 TypeScript를 함께 사용하는 방법 익히기
- 정적 사이트 생성의 이점 파악하기
- 실제 프로젝트에 적용하는 방법 배우기
1. Gatsby: 현대적인 웹 개발의 신세계 🌟
Gatsby는 React 기반의 정적 사이트 생성기입니다. "정적 사이트 생성기"라고 하면 뭔가 딱딱하고 지루할 것 같지만, 전혀 그렇지 않아요! Gatsby는 마치 레고 블록처럼 웹사이트를 조립할 수 있게 해주는 멋진 도구예요. 🧱✨
1.1 Gatsby의 특징
- 빠른 속도: Gatsby로 만든 사이트는 번개처럼 빠릅니다! ⚡
- 플러그인 생태계: 다양한 기능을 쉽게 추가할 수 있어요. 마치 스마트폰에 앱을 설치하는 것처럼 간단해요! 📱
- SEO 친화적: 검색 엔진이 여러분의 사이트를 사랑하게 될 거예요. 💖
- Progressive Web App: 모바일에서도 앱처럼 동작하는 웹사이트를 만들 수 있어요. 📱💻
Gatsby를 사용하면, 재능넷과 같은 복잡한 사이트도 효율적으로 만들 수 있어요. 사용자들이 재능을 빠르게 검색하고 거래할 수 있는 환경을 제공할 수 있죠!
1.2 Gatsby의 작동 원리
Gatsby는 마법사처럼 동작해요. 여러분이 콘텐츠를 작성하면, Gatsby가 그것을 가져와 최적화된 HTML, CSS, JavaScript로 변환합니다. 이 과정을 그림으로 표현해볼까요?
이렇게 Gatsby는 여러분의 콘텐츠를 받아서 최적화된 웹사이트로 변신시켜줍니다. 마치 요리사가 신선한 재료로 맛있는 요리를 만드는 것처럼요! 🍳👨🍳
1.3 Gatsby vs 다른 프레임워크
웹 개발 세계에는 다양한 프레임워크가 있어요. Gatsby가 어떻게 다른지 한번 비교해볼까요?
프레임워크 | 장점 | 단점 |
---|---|---|
Gatsby | 빠른 속도, 플러그인 생태계, SEO 친화적 | 학습 곡선이 있음, 동적 콘텐츠 처리에 제한 |
Next.js | 서버 사이드 렌더링, 정적/동적 페이지 모두 지원 | 설정이 복잡할 수 있음 |
Create React App | 쉬운 설정, React 앱 빠른 시작 | SEO에 불리, 서버 사이드 렌더링 없음 |
각 프레임워크는 자신만의 특징이 있어요. Gatsby는 특히 빠른 속도와 SEO 최적화가 필요한 프로젝트에 딱이에요. 예를 들어, 재능넷과 같은 사이트는 사용자들이 빠르게 정보를 찾고, 검색 엔진에서도 잘 노출되어야 하죠. 이런 경우 Gatsby가 완벽한 선택이 될 수 있어요!
1.4 Gatsby로 할 수 있는 멋진 것들
Gatsby로 무엇을 만들 수 있을까요? 가능성은 무한해요! 🌈
- 🖥️ 개인 포트폴리오 웹사이트
- 📰 뉴스 또는 블로그 사이트
- 🛒 e-커머스 플랫폼
- 🎨 디지털 아트 갤러리
- 📚 온라인 학습 플랫폼
여러분의 상상력이 곧 한계예요. Gatsby는 여러분의 아이디어를 현실로 만들어주는 마법 지팡이 같은 존재랍니다! 🧙♂️✨
🚀 Mini Challenge: Gatsby로 만들고 싶은 웹사이트를 상상해보세요. 어떤 기능이 필요할까요? 어떤 플러그인을 사용하면 좋을까요? 잠시 생각해보고 아이디어를 메모해보세요!
2. TypeScript: 타입의 마법사 🧙♂️
자, 이제 TypeScript라는 멋진 친구를 소개할 시간이에요! TypeScript는 JavaScript의 슈퍼셋으로, 타입을 추가한 프로그래밍 언어예요. 마치 JavaScript에 슈퍼 파워를 부여한 것과 같죠! 💪
2.1 TypeScript의 특징
- 정적 타입 검사: 코드를 실행하기 전에 오류를 잡아냅니다. 마치 맞춤법 검사기처럼요! 📝
- 향상된 IDE 지원: 코드 자동 완성, 리팩토링 등이 더 강력해집니다. 🖥️
- 객체 지향 프로그래밍 지원: 클래스, 인터페이스 등을 사용할 수 있어요. 🏗️
- JavaScript와의 호환성: 기존 JavaScript 코드를 그대로 사용할 수 있어요. 🤝
TypeScript를 사용하면, 재능넷과 같은 복잡한 웹 애플리케이션을 더 안정적으로 개발할 수 있어요. 사용자의 프로필, 재능 정보, 거래 내역 등을 타입으로 정의하면 실수를 줄이고 개발 속도를 높일 수 있죠!
2.2 TypeScript vs JavaScript
TypeScript와 JavaScript의 차이점을 간단한 예제로 살펴볼까요?
JavaScript
function greet(name) {
return "Hello, " + name + "!";
}
console.log(greet("Alice")); // 정상 동작
console.log(greet(42)); // 이상하지만 오류 없음
TypeScript
function greet(name: string): string {
return "Hello, " + name + "!";
}
console.log(greet("Alice")); // 정상 동작
console.log(greet(42)); // 컴파일 오류!
보셨나요? TypeScript는 함수의 매개변수와 반환값에 타입을 지정할 수 있어요. 이렇게 하면 잘못된 타입의 데이터가 들어오는 것을 미리 방지할 수 있답니다. 마치 경비원이 문 앞에서 초대장을 확인하는 것처럼요! 🚪👮♂️
2.3 TypeScript의 주요 개념
TypeScript에는 몇 가지 중요한 개념들이 있어요. 이 개념들을 이해하면 TypeScript의 진정한 힘을 느낄 수 있답니다!
1. 인터페이스 (Interface)
객체의 구조를 정의하는 방법이에요. 마치 청사진 같은 거죠!
interface User {
name: string;
age: number;
email?: string; // 선택적 속성
}
const user: User = {
name: "Alice",
age: 30
};
2. 제네릭 (Generics)
타입을 마치 변수처럼 사용할 수 있게 해주는 강력한 도구예요.
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString");
3. 유니온 타입 (Union Types)
여러 타입 중 하나일 수 있음을 나타내요. 마치 여러 가지 맛 중에서 고르는 것처럼요!
let myFavorite: string | number;
myFavorite = "TypeScript"; // OK
myFavorite = 42; // 또한 OK
이런 개념들을 활용하면, 재능넷과 같은 플랫폼에서 다양한 유형의 사용자, 재능, 거래 정보 등을 더 정확하고 유연하게 다룰 수 있어요. 예를 들어, 재능의 가격을 숫자나 "무료"라는 문자열로 표현할 수 있겠죠?
2.4 TypeScript의 장점
TypeScript를 사용하면 어떤 점이 좋을까요? 한번 자세히 살펴볼까요? 🕵️♀️
- 버그 감소: 타입 체크로 인해 많은 버그를 사전에 방지할 수 있어요. 마치 질병을 예방하는 백신 같아요! 💉
- 코드 가독성 향상: 타입 정보가 있어 코드를 이해하기 쉬워져요. 주석이 없어도 코드가 스스로 설명하는 것 같죠! 📖
- 리팩토링 용이성: IDE의 강력한 지원으로 대규모 리팩토링도 두렵지 않아요. 마치 강력한 청소기로 집 안 구석구석을 정리하는 것처럼요! 🧹
- 팀 협업 개선: 명확한 타입 정의로 팀원 간 의사소통이 원활해져요. 모두가 같은 언어로 이야기하는 것 같죠! 🗣️
이런 장점들 덕분에 TypeScript는 대규모 프로젝트에서 특히 빛을 발해요. 재능넷처럼 다양한 기능과 복잡한 데이터 구조를 가진 웹 애플리케이션을 개발할 때 TypeScript의 힘을 제대로 느낄 수 있답니다!
2.5 TypeScript 실전 팁
TypeScript를 더 잘 활용하기 위한 몇 가지 팁을 소개할게요! 🎩✨
🔍 Tip 1: 엄격한 타입 체크 사용하기
tsconfig.json 파일에서 strict 옵션을 true로 설정하세요. 이렇게 하면 TypeScript의 타입 체크가 더욱 엄격해져요!
{
"compilerOptions": {
"strict": true
// 다른 옵션들...
}
}
🎨 Tip 2: 타입 별칭 활용하기
복잡한 타입을 간단하게 표현할 수 있어요. 마치 긴 이름 대신 별명을 부르는 것처럼요!
type Point = {
x: number;
y: number;
};
function printPoint(point: Point) {
console.log(`x: ${point.x}, y: ${point.y}`);
}
🛠 Tip 3: 유틸리티 타입 사용하기
TypeScript에는 타입을 변형하는 데 사용할 수 있는 유용한 유틸리티 타입들이 있어요.
interface User {
id: number;
name: string;
email: string;
}
type PartialUser = Partial<User>; // 모든 속성이 선택적인 새로운 타입
type UserWithoutEmail = Omit<User, 'email'>; // email을 제외한 새로운 타입
이런 팁들을 활용하면 TypeScript로 더 깔끔하고 안전한 코드를 작성할 수 있어요. 재능넷과 같은 복잡한 웹 애플리케이션을 개발할 때 이런 기술들이 큰 도움이 될 거예요!
🚀 Mini Challenge: TypeScript를 사용해서 간단한 사용자 프로필 인터페이스를 만들어보세요. 이름, 나이, 이메일(선택), 보유 재능(배열) 등을 포함해보는 건 어떨까요? 그리고 이 인터페이스를 사용해 샘플 데이터를 만들어보세요!
3. Gatsby와 TypeScript의 환상의 콜라보 🎭
자, 이제 우리의 두 주인공 Gatsby와 TypeScript를 함께 사용해볼 시간이에요! 이 둘을 합치면 정말 놀라운 일이 벌어집니다. 마치 초콜릿과 땅콩버터의 조합처럼 말이죠! 🍫🥜
3.1 Gatsby 프로젝트에 TypeScript 도입하기
Gatsby 프로젝트에 TypeScript를 도입하는 것은 생각보다 쉬워요. 마치 레고 블록을 끼우는 것처럼 간단하답니다! 👷♂️
- 새 Gatsby 프로젝트 생성: 먼저 새로운 Gatsby 프로젝트를 만들어볼까요?
- TypeScript 설치: 이제 TypeScript와 관련 플러그인을 설치해요.
- gatsby-config.js 수정: Gatsby 설정 파일에 TypeScript 플러그인을 추가해요.
- tsconfig.json 생성: TypeScript 설정 파일을 만들어요.
npx gatsby new my-typescript-site
cd my-typescript-site
npm install --save-dev typescript @types/react @types/react-dom @types/node
npm install gatsby-plugin-typescript
module.exports = {
plugins: [`gatsby-plugin-typescript`],
// 다른 설정들...
}
{
"compilerOptions": {
"module": "commonjs",
"target": "esnext",
"jsx": "preserve",
"lib": ["dom", "esnext"],
"strict": true,
"noEmit": true,
"isolatedModules": true,
"esModuleInterop": true,
"noUnusedLocals": false,
"allowJs": true
},
"exclude": ["node_modules", "public", ".cache"]
}
이렇게 하면 기본적인 설정은 끝났어요! 이제 재능넷과 같은 멋진 프로젝트를 TypeScript로 개발할 준비가 된 거예요. 🎉
3.2 Gatsby와 TypeScript로 컴포넌트 만들기
이제 실제로 TypeScript를 사용해 Gatsby 컴포넌트를 만들어볼까요? 간단한 예제로 시작해봐요!
Header 컴포넌트 만들기
src/components/Header.tsx 파일을 만들고 다음 코드를 작성해보세요:
import React from 'react'
interface HeaderProps {
siteTitle: string;
}
const Header: React.FC<HeaderProps> = ({ siteTitle }) => (
<header style={{ background: `rebeccapurple`, marginBottom: `1.45rem` }}>
<div style={{ margin: `0 auto`, maxWidth: 960, padding: `1.45rem 1.0875rem` }}>
<h1 style={{ margin: 0 }}>
<a href="/" style={{ color: `white`, textDecoration: `none` }}>
{siteTitle}
</a>
</h1>
</div>
</header>
)
export default Header
보셨나요? TypeScript를 사용하면 컴포넌트의 props 타입을 명확하게 정의할 수 있어요. 이렇게 하면 잘못된 타입의 props를 전달하는 실수를 미리 방지할 수 있답니다. 마치 요리 재료를 미리 정확히 준비해두는 것과 같죠! 👨🍳
3.3 페이지 컴포넌트에 TypeScript 적용하기
Gatsby에서는 pages 디렉토리에 있는 컴포넌트가 자동으로 페이지가 됩니다. 이 페이지 컴포넌트에도 TypeScript를 적용해볼까요?
Index 페이지 만들기
src/pages/index.tsx 파일을 만들고 다음 코드를 작성해보세요:
import React from 'react'
import { PageProps } from 'gatsby'
import Layout from '../components/layout'
import SEO from '../components/seo'
const IndexPage: React.FC<PageProps> = () => (
<Layout>
<SEO title="Home" />
<h1>안녕하세요, 재능넷에 오신 것을 환영합니다!</h1>
<p>여기서 당신의 재능을 마음껏 펼쳐보세요.</p>
</Layout>
)
export default IndexPage
이렇게 하면 페이지 컴포넌트에도 TypeScript의 타입 체크 기능을 적용할 수 있어요. PageProps 타입을 사용하면 Gatsby가 페이지 컴포넌트에 전달하는 props의 타입을 정확히 알 수 있죠!
3.4 GraphQL과 TypeScript 함께 사용하기
Gatsby의 강력한 기능 중 하나는 GraphQL을 통한 데이터 쿼리입니다. TypeScript와 함께 사용하면 더욱 강력해져요!
GraphQL 쿼리 결과에 타입 적용하기
src/pages/talents.tsx 파일을 만들고 다음 코드를 작성해보세요:
import React from 'react'
import { graphql, PageProps } from 'gatsby'
interface TalentData {
allTalents: {
edges: {
node: {
id: string
title: string
description: string
}
}[]
}
}
const TalentsPage: React.FC<PageProps<TalentData>> = ({ data }) => (
<>
<h1>재능 목록</h1>
<ul>
{data.allTalents.edges.map(({ node }) => (
<li key={node.id}>
<h2>{node.title}</h2>
<p>{node.description}</p>
</li>
))}
</ul>
</>
)
export const query = graphql`
query TalentsQuery {
allTalents {
edges {
node {
id
title
description
}
}
}
}
`
export default TalentsPage
이렇게 하면 GraphQL 쿼리 결과의 타입을 정확히 지정할 수 있어요. 데이터를 사용할 때 자동 완성 기능도 사용할 수 있고, 잘못된 필드에 접근하는 실수도 방지할 수 있답니다. 마치 데이터베이스에 안전장치를 달아놓은 것 같죠? 🔐
3.5 Gatsby와 TypeScript의 시너지 효과
Gatsby와 TypeScript를 함께 사용하면 정말 멋진 일들이 일어나요! 🎭✨
- 개발 생산성 향상: 자동 완성과 타입 체크로 개발 속도가 빨라져요. 마치 터보 엔진을 단 것처럼요! 🚀
- 버그 감소: 컴파일 타임에 많은 오류를 잡아낼 수 있어요. 디버깅 시간이 크게 줄어들죠! 🐛🔍
- 코드 품질 개선: 타입 정의로 인해 코드의 의도가 명확해져요. 마치 코드에 상세한 설명서를 붙여놓은 것 같죠! 📚
- 리팩토링 용이성: 타입 시스템 덕분에 대규모 리팩토링도 두렵지 않아요. 변경 사항의 영향을 쉽게 파악할 수 있거든요! 🔧
이런 장점들 덕분에 재능넷과 같은 복잡한 웹 애플리케이션을 개발할 때 Gatsby와 TypeScript의 조합은 정말 강력한 무기가 됩니다. 사용자 프로필, 재능 정보, 거래 시스템 등 복잡한 데이터 구조를 안전하고 효율적으로 다룰 수 있어요!
3.6 실전 팁: Gatsby + TypeScript 프로젝트 구조화
대규모 프로젝트를 위한 효율적인 파일 구조를 살펴볼까요? 🗂️
my-gatsby-typescript-project/
├── src/
│ ├── components/
│ │ ├── Layout/
│ │ │ ├── Layout.tsx
│ │ │ └── index.ts
│ │ ├── Header/
│ │ │ ├── Header.tsx
│ │ │ └── index.ts
│ │ └── ...
│ ├── pages/
│ │ ├── index.tsx
│ │ ├── talents.tsx
│ │ └── ...
│ ├── templates/
│ │ ├── TalentPage.tsx
│ │ └── ...
│ ├── hooks/
│ │ ├── useSiteMetadata.ts
│ │ └── ...
│ ├── utils/
│ │ ├── formatDate.ts
│ │ └── ...
│ └── types/
│ ├── talent.ts
│ └── ...
├── gatsby-config.js
├── gatsby-node.js
├── tsconfig.json
└── package.json
이런 구조를 사용하면 프로젝트를 깔끔하게 관리할 수 있어요. 각 컴포넌트, 페이지, 유틸리티 함수 등이 명확히 구분되어 있어 협업할 때도 편리하답니다! 🤝
🚀 Mini Challenge: 위의 프로젝트 구조를 참고해서 재능넷의 '재능 상세 페이지'를 위한 컴포넌트와 페이지를 만들어보세요. 재능의 제목, 설명, 가격, 판매자 정보 등을 포함해보는 건 어떨까요? TypeScript로 타입을 정의하고, GraphQL로 데이터를 쿼리해보세요!
4. 정적 사이트 생성의 마법: Gatsby + TypeScript의 힘 💪
자, 이제 Gatsby와 TypeScript를 결합해 정적 사이트를 생성하는 과정을 자세히 살펴볼까요? 이 과정은 마치 요리사가 최고의 재료로 맛있는 요리를 만드는 것과 같아요! 👨🍳✨
4.1 빌드 프로세스 이해하기
Gatsby의 빌드 프로세스는 여러 단계로 이루어져 있어요. 각 단계를 이해하면 최적화된 사이트를 만들 수 있답니다!
- 데이터 소싱: GraphQL을 통해 다양한 소스에서 데이터를 가져와요.
- 데이터 변환: 가져온 데이터를 필요한 형태로 변환해요.
- 페이지 생성: 데이터를 기반으로 정적 페이지를 생성해요.
- 최적화: 이미지 최적화, 코드 분할 등을 수행해요.
- HTML 생성: 각 페이지에 대한 HTML 파일을 생성해요.
이 과정에서 TypeScript는 타입 안정성을 제공하여 각 단계가 오류 없이 진행되도록 도와줍니다. 마치 요리 과정에서 정확한 계량을 하는 것과 같죠! ⚖️
4.2 성능 최적화 기법
Gatsby와 TypeScript를 사용하면 웹사이트의 성능을 극대화할 수 있어요. 몇 가지 핵심 기법을 살펴볼까요?
1. 이미지 최적화
Gatsby의 이미지 처리 기능을 TypeScript와 함께 사용해보세요:
import React from 'react'
import { graphql, useStaticQuery } from 'gatsby'
import Img from 'gatsby-image'
const TalentImage: React.FC<{ talentId: string }> = ({ talentId }) => {
const data = useStaticQuery(graphql`
query {
allTalentImages {
edges {
node {
id
childImageSharp {
fluid(maxWidth: 300) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`)
const image = data.allTalentImages.edges.find(
edge => edge.node.id === talentId
)?.node.childImageSharp.fluid
return image ? <Img fluid={image} alt="Talent" /> : null
}
export default TalentImage
이렇게 하면 이미지가 자동으로 최적화되어 로딩 속도가 빨라져요. 사용자들이 재능넷의 재능 이미지를 빠르게 볼 수 있겠죠! 🖼️💨
4.3 SEO 최적화
검색 엔진 최적화(SEO)는 웹사이트의 성공에 매우 중요해요. Gatsby와 TypeScript를 사용하면 SEO도 쉽게 최적화할 수 있답니다!
SEO 컴포넌트 만들기
src/components/SEO.tsx 파일을 만들고 다음 코드를 작성해보세요:
import React from 'react'
import { Helmet } from 'react-helmet'
import { useStaticQuery, graphql } from 'gatsby'
interface SEOProps {
title: string
description?: string
lang?: string
meta?: Array<{ name: string; content: string }>
}
const SEO: React.FC<SEOProps> = ({ description = '', lang = 'en', meta = [], title }) => {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
author
}
}
}
`
)
const metaDescription = description || site.siteMetadata.description
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
titleTemplate={`%s | ${site.siteMetadata.title}`}
meta={[
{
name: `description`,
content: metaDescription,
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:card`,
content: `summary`,
},
{
name: `twitter:creator`,
content: site.siteMetadata.author,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: metaDescription,
},
].concat(meta)}
/>
)
}
export default SEO
이 SEO 컴포넌트를 사용하면 각 페이지의 메타 정보를 쉽게 관리할 수 있어요. 재능넷의 각 재능 페이지가 검색 엔진에 잘 노출될 수 있겠죠! 🔍📈
4.4 동적 기능 추가하기
정적 사이트라고 해서 모든 것이 정적일 필요는 없어요. Gatsby와 TypeScript를 사용하면 동적 기능도 쉽게 추가할 수 있답니다!
실시간 검색 기능 추가하기
src/components/Search.tsx 파일을 만들고 다음 코드를 작성해보세요:
import React, { useState, useEffect } from 'react'
import { graphql, useStaticQuery } from 'gatsby'
interface Talent {
id: string
title: string
description: string
}
const Search: React.FC = () => {
const data = useStaticQuery(graphql`
query {
allTalents {
nodes {
id
title
description
}
}
}
`)
const [searchTerm, setSearchTerm] = useState('')
const [searchResults, setSearchResults] = useState<Talent[]>([])
useEffect(() => {
const results = data.allTalents.nodes.filter((talent: Talent) =>
talent.title.toLowerCase().includes(searchTerm.toLowerCase())
)
setSearchResults(results)
}, [data, searchTerm])
return (
<div>
<input
type="text"
placeholder="재능 검색..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<ul>
{searchResults.map((talent) => (
<li key={talent.id}>
<h3>{talent.title}</h3>
<p>{talent.description}</p>
</li>
))}
</ul>
</div>
)
}
export default Search
이렇게 하면 사용자가 실시간으로 재능을 검색할 수 있어요. 재능넷의 사용자 경험이 한층 더 좋아지겠죠! 🔍✨
4.5 배포 및 호스팅
Gatsby로 만든 정적 사이트는 다양한 플랫폼에 쉽게 배포할 수 있어요. 몇 가지 인기 있는 옵션을 살펴볼까요?
- Netlify: GitHub와 연동하여 자동 배포가 가능해요. 무료 HTTPS와 CDN도 제공합니다.
- Vercel: Next.js로 유명하지만 Gatsby 사이트도 훌륭하게 지원해요.
- GitHub Pages: GitHub 저장소와 직접 연동되어 무료로 호스팅할 수 있어요.
- Amazon S3 + CloudFront: 대규모 트래픽을 처리해야 한다면 좋은 선택이 될 수 있어요.
재능넷과 같은 서비스는 사용자가 많아질수록 안정적인 호스팅이 중요해져요. Netlify나 Vercel과 같은 플랫폼을 사용하면 초기에는 무료로 시작하고, 나중에 필요에 따라 스케일업할 수 있답니다! 🚀
🚀 Mini Challenge: 지금까지 만든 재능넷 프로젝트를 GitHub에 push하고, Netlify에 배포해보세요. 자동 배포 설정을 해두면, 코드를 수정할 때마다 자동으로 사이트가 업데이트된답니다! 멋지지 않나요? 😎
5. 실전 프로젝트: 재능넷 구현하기 🛠️
자, 이제 우리가 배운 모든 것을 종합해서 재능넷을 실제로 구현해볼 시간이에요! 이 과정을 통해 Gatsby와 TypeScript의 진정한 힘을 경험할 수 있을 거예요. 준비되셨나요? Let's go! 🚀
5.1 프로젝트 설정
먼저 프로젝트를 설정해볼까요? 터미널을 열고 다음 명령어를 실행해주세요:
npx gatsby new talent-net https://github.com/gatsbyjs/gatsby-starter-default
cd talent-net
npm install --save-dev typescript @types/react @types/react-dom @types/node
npm install gatsby-plugin-typescript
그리고 gatsby-config.js 파일에 다음 내용을 추가해주세요:
module.exports = {
// ... 기존 설정 ...
plugins: [
`gatsby-plugin-typescript`,
// ... 다른 플러그인들 ...
],
}
5.2 타입 정의하기
재능넷의 핵심 개체들의 타입을 정의해볼까요? src/types/index.ts 파일을 만들고 다음 내용을 작성해주세요:
export interface Talent {
id: string
title: string
description: string
price: number
category: string
seller: User
}
export interface User {
id: string
name: string
email: string
talents: Talent[]
}
export interface Order {
id: string
talent: Talent
buyer: User
seller: User
status: 'pending' | 'completed' | 'cancelled'
createdAt: Date
}
이렇게 타입을 정의해두면 개발 과정에서 실수를 줄이고 코드의 가독성을 높일 수 있어요! 👀✨
5.3 GraphQL로 데이터 쿼리하기
이제 재능 목록을 가져오는 GraphQL 쿼리를 만들어볼까요? src/pages/index.tsx 파일을 다음과 같이 수정해주세요:
import React from 'react'
import { graphql, PageProps } from 'gatsby'
import Layout from '../components/layout'
import SEO from '../components/seo'
import { Talent } from '../types'
interface DataProps {
allTalents: {
edges: {
node: Talent
}[]
}
}
const IndexPage: React.FC<PageProps<DataProps>> = ({ data }) => (
<Layout>
<SEO title="Home" />
<h1>재능넷에 오신 것을 환영합니다!</h1>
<ul>
{data.allTalents.edges.map(({ node }) => (
<li key={node.id}>
<h2>{node.title}</h2>
<p>{node.description}</p>
<p>가격: {node.price}원</p>
</li>
))}
</ul>
</Layout>
)
export const query = graphql`
query {
allTalents {
edges {
node {
id
title
description
price
}
}
}
}
`
export default IndexPage
이렇게 하면 메인 페이지에서 모든 재능 목록을 볼 수 있어요. 타입스크립트 덕분에 data의 구조를 정확히 알 수 있죠! 👍
5.4 동적 페이지 생성하기
각 재능에 대한 상세 페이지를 동적으로 생성해볼까요? gatsby-node.js 파일을 다음과 같이 수정해주세요:
exports.createPages = async ({ actions, graphql }) => {
const { createPage } = actions
const result = await graphql(`
{
allTalents {
edges {
node {
id
}
}
}
}
`)
result.data.allTalents.edges.forEach(({ node }) => {
createPage({
path: `/talent/${node.id}`,
component: path.resolve(`src/templates/talent-detail.tsx`),
context: {
id: node.id,
},
})
})
}
그리고 src/templates/talent-detail.tsx 파일을 만들어주세요:
import React from 'react'
import { graphql, PageProps } from 'gatsby'
import Layout from '../components/layout'
import SEO from '../components/seo'
import { Talent } from '../types'
interface DataProps {
talent: Talent
}
const TalentDetail: React.FC<PageProps<DataProps>> = ({ data }) => {
const talent = data.talent
return (
<Layout>
<SEO title={talent.title} />
<h1>{talent.title}</h1>
<p>{talent.description}</p>
<p>가격: {talent.price}원</p>
<p>판매자: {talent.seller.name}</p>
</Layout>
)
}
export const query = graphql`
query($id: String!) {
talent(id: { eq: $id }) {
id
title
description
price
seller {
name
}
}
}
`
export default TalentDetail
이제 각 재능에 대한 상세 페이지가 동적으로 생성됩니다. 멋지죠? 🎉
5.5 스타일링 추가하기
마지막으로 우리의 재능넷에 스타일을 입혀볼까요? styled-components를 사용해볼게요. 먼저 설치해주세요:
npm install styled-components @types/styled-components gatsby-plugin-styled-components
그리고 gatsby-config.js에 플러그인을 추가해주세요:
module.exports = {
// ... 기존 설정 ...
plugins: [
`gatsby-plugin-styled-components`,
// ... 다른 플러그인들 ...
],
}
이제 src/components/TalentCard.tsx 파일을 만들어 스타일링된 재능 카드 컴포넌트를 만들어볼까요?
import React from 'react'
import styled from 'styled-components'
import { Link } from 'gatsby' import { Talent } from '../types'
const Card = styled.div`
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
transition: all 0.3s ease;
&:hover {
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
transform: translateY(-5px);
}
`
const Title = styled.h2`
color: #333;
font-size: 1.5em;
margin-bottom: 8px;
`
const Description = styled.p`
color: #666;
font-size: 1em;
margin-bottom: 8px;
`
const Price = styled.p`
color: #e74c3c;
font-weight: bold;
font-size: 1.2em;
`
interface TalentCardProps {
talent: Talent
}
const TalentCard: React.FC<talentcardprops> = ({ talent }) => (
<link to="{`/talent/${talent.id}`}" style="{{" textdecoration:>
<card>
<title>{talent.title}</title>
<description>{talent.description}</description>
<price>{talent.price}원</price>
</card>
)
export default TalentCard
</talentcardprops>
이제 이 TalentCard 컴포넌트를 사용해 메인 페이지를 더 멋지게 꾸며볼까요? src/pages/index.tsx 파일을 다음과 같이 수정해주세요:
import React from 'react'
import { graphql, PageProps } from 'gatsby'
import styled from 'styled-components'
import Layout from '../components/layout'
import SEO from '../components/seo'
import TalentCard from '../components/TalentCard'
import { Talent } from '../types'
const TalentGrid = styled.div`
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
padding: 20px;
`
interface DataProps {
allTalents: {
edges: {
node: Talent
}[]
}
}
const IndexPage: React.FC<pageprops>> = ({ data }) => (
<layout>
<seo title="Home"></seo>
<h1>재능넷에 오신 것을 환영합니다!</h1>
<talentgrid>
{data.allTalents.edges.map(({ node }) => (
<talentcard key="{node.id}" talent="{node}"></talentcard>
))}
</talentgrid>
</layout>
)
export const query = graphql`
query {
allTalents {
edges {
node {
id
title
description
price
}
}
}
}
`
export default IndexPage
</pageprops>
와우! 이제 우리의 재능넷이 정말 멋지게 변신했어요! 🎨✨
5.6 기능 추가: 검색 기능
사용자 경험을 더욱 향상시키기 위해 검색 기능을 추가해볼까요? src/components/Search.tsx 파일을 만들어주세요:
import React, { useState } from 'react'
import styled from 'styled-components'
import { useStaticQuery, graphql } from 'gatsby'
import TalentCard from './TalentCard'
import { Talent } from '../types'
const SearchContainer = styled.div`
margin-bottom: 20px;
`
const SearchInput = styled.input`
width: 100%;
padding: 10px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px;
`
const Search: React.FC = () => {
const [searchTerm, setSearchTerm] = useState('')
const data = useStaticQuery(graphql`
query {
allTalents {
edges {
node {
id
title
description
price
}
}
}
}
`)
const talents: Talent[] = data.allTalents.edges.map(({ node }: { node: Talent }) => node)
const filteredTalents = talents.filter(talent =>
talent.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
talent.description.toLowerCase().includes(searchTerm.toLowerCase())
)
return (
<searchcontainer>
<searchinput type="text" placeholder="재능 검색..." value="{searchTerm}" onchange="{(e)"> setSearchTerm(e.target.value)}
/>
{filteredTalents.map(talent => (
<talentcard key="{talent.id}" talent="{talent}"></talentcard>
))}
</searchinput></searchcontainer>
)
}
export default Search
이제 이 Search 컴포넌트를 메인 페이지에 추가해볼까요? src/pages/index.tsx 파일을 다음과 같이 수정해주세요:
import React from 'react'
import { PageProps } from 'gatsby'
import Layout from '../components/layout'
import SEO from '../components/seo'
import Search from '../components/Search'
const IndexPage: React.FC<pageprops> = () => (
<layout>
<seo title="Home"></seo>
<h1>재능넷에 오신 것을 환영합니다!</h1>
<search></search>
</layout>
)
export default IndexPage
</pageprops>
멋져요! 이제 사용자들이 원하는 재능을 쉽게 찾을 수 있게 되었어요. 🔍✨
5.7 마무리 및 배포
자, 이제 우리의 재능넷이 거의 완성되었어요! 마지막으로 프로젝트를 빌드하고 배포해볼까요?
- 먼저 프로젝트를 빌드해주세요:
gatsby build
- 빌드된 사이트를 로컬에서 확인해보세요:
gatsby serve
- 모든 것이 잘 작동한다면, 이제 배포할 차례예요! Netlify를 사용해 배포해볼까요?
- Netlify 계정을 만들고 새 사이트를 추가하세요.
- GitHub 저장소와 연결하세요.
- 빌드 설정에서 빌드 명령어를
gatsby build
로, 퍼블릭 디렉토리를public/
로 설정하세요. - "Deploy site" 버튼을 클릭하세요!
축하합니다! 🎉 이제 여러분의 재능넷이 전 세계에 공개되었어요. Gatsby와 TypeScript의 강력한 조합으로 만든 빠르고 안정적인 웹사이트를 만들어냈답니다!
🚀 Final Challenge: 지금까지 만든 재능넷에 새로운 기능을 추가해보는 건 어떨까요? 예를 들어, 사용자 인증 기능이나 재능 등록 기능을 추가해볼 수 있어요. 또는 결제 시스템을 연동해볼 수도 있겠죠. 여러분의 상상력을 마음껏 펼쳐보세요!
이렇게 해서 우리는 Gatsby와 TypeScript를 사용해 멋진 웹사이트를 만들어보았어요. 이 과정에서 정적 사이트 생성의 장점, TypeScript의 타입 안정성, 그리고 현대적인 웹 개발 도구들의 강력함을 경험해보았죠. 앞으로 여러분이 만들 멋진 프로젝트들이 기대되네요! 화이팅! 💪😊