Gatsby 프로젝트 생성

Modern Stack
2025.09.17
Gatsby 프로젝트 생성

특징

React, GraphQL 기반 정적 페이지 (Static Site Generator) 생성
JAM Stack (Javascript, API, MarkUp Stack) 기반 프레임워크 - 빠르고 안전하고 스케일링 하기 쉬움

  • 서버와 통신, 동적 생성(Next.js)과 달리 서버 없이 정적 사이트 생성
  • 빌드 시 각 페이지에 대한 파일 생성, 저장(CDN) 후 요청 시 재사용
  • CDN(Content Delivery Network) 통해 제공
  • 기업 소개 페이지, 블로그, 포트폴리오 작업에 적합
  • 다양한 플러그인 사용하여 쉽게 제작 가능

Gatsby 프로젝트 생성

npx gatsby-cli new "NEW PROJECT"

Directory

  • contents: 포스트 관련 파일 (markdown, img)
  • src
    • components: React Components
    • hooks
    • pages: 파일 명으로 페이지 접근가능
    • templates: 여러 콘텐츠 Components, Gatsby에서 제공하는 API로 페이지 생성
      파일명으로 접근 불가
  • static: 정적 파일

Gatsby Rendering

  gatsby-browser.js (브라우저: 클라이언트) gatsby-ssr.js (서버)
  페이지 로드 후 HTML 생성 시
예시 전역 CSS Import, 이벤트 제어, 브라우저 전용 API 사용 시 mata/script/style preload(폰트)
  • 구글 태그 관리자
gatsby-ssr.js
/**
 * @type {import('gatsby').GatsbySSR['onRenderBody']}
 */
const { gtmNoscript, gtmScript } = require('./src/components/Common/gtm-tag')

exports.onRenderBody = ({
  setHtmlAttributes,
  setHeadComponents,
  setPreBodyComponents,
}) => {
  setHtmlAttributes({ lang: `en` })
  setHeadComponents([gtmScript])
  setPreBodyComponents([gtmNoscript])
}

TypeScript

MicroSoft에서 개발, 오픈 소스 프로그래밍 언어
Javascript에 타입을 부여한 언어 (Javascript로 컴파일 되어 동작)

  • 컴파일 단계에서 에러를 알려주어 오류 방지
  • 변수와 함수의 타입을 알 수 있어 유지보수 용이
yarn add typescript --dev gatsby-plugin-typescript
gatsby-config.js
module.exports = {
	plugins: [
    {
      resolve: 'gatsby-plugin-typescript',
      options: {
        isTSX: true,
        allExtensions: true,
      },
    },
    ...
  ],
}
yarn tsc --init
tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "allowJs": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "baseUrl": "./src",
    "paths": {
      "components/*": ["./components/*"],
      "utils/*": ["./utils/*"],
      "hooks/*": ["./hooks/*"]
    },
    "strict": true,
    "jsx": "preserve",
    "jsxImportSource": "@emotion/react",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  },
  "include": ["src/**/*.tsx"],
  "exclude": ["node_modules"]
}
gatsby-node.js
/**
 * @type {import('gatsby').GatsbyNode['createPages']}
*/
const path = require('path')

// Setup Import Alias
exports.onCreateWebpackConfig = ({ getConfig, actions }) => {
  const output = getConfig().output || {}

  actions.setWebpackConfig({
    output,
    resolve: {
      alias: {
        components: path.resolve(__dirname, 'src/components'),
        utils: path.resolve(__dirname, 'src/utils'),
        hooks: path.resolve(__dirname, 'src/hooks'),
      },
    },
  })
}

함수형 컴포넌트

import {FunctionComponent} from 'react'

const SomePage: FunctionComponent = function(){
	return <Text />
}
export default SomePage

Generic

클래스나 함수에서 사용할 타입을 미리 명시 후 사용할 때 결정

import {FunctionComponent} from 'react'

interface SomeProps {
	text: string
}

const SomePage: FunctionComponent<SomeProps> = function(){
	return <Text />
}
export default SomePage

interface 와 type 차이

  • interface
    • 객체 타입 정의 시(공개 API) 사용
    • extends 확장 가능
interface SomeProps {
	title: string
}
interface SomeProps {  // 선언적 확장도 가능
	body: string
}
interface SomeProps2 extends SomeProps {
	SomeBody: string
}
const MyContents: SomeProps2 = {
	title: '...',
	body: '...',
	SomeBody: '...',
}
  • type
    • 병합 불가
    • 확장 시 & 연산자 사용
    • computed value 사용 가능
type SomeProps{
	title: string
} & {
	body: string
}

type SomeArray = {
	[key in Somes]: string
}

EmotionJS

styled-components 의 기능과 거의 동일하며 번들 용량이 작다

yarn add gatsby-plugin-emotion @emotion/react @emotion/styled
gatsby-config.js
module.exports = {
	plugins: [
		...
    `gatsby-plugin-emotion`,
    ...
  ],
}

Global 스타일 지정 방법

import { Global, css } from '@emotion/react'
const defaultStyle = css`
  body {
    margin: 0;
    padding: 0;
    font-family: Pretendard, system-ui, -apple-system, BlinkMacSystemFont,
      'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
      'Helvetica Neue', sans-serif;
    color: #333;
  }
`
const GlobalStyle: FunctionComponent = function () {
  return <Global styles={defaultStyle} />
}
export default GlobalStyle

css 정의 및 적용

import { css } from '@emotion/react'
const SomeStyle = css`
	font-size:14px;
`
...
<div css={SomeStyle}></div>
...

Styled Component 생성 방법 1 : .(dot)을 통해 함수 호출

Kebab Case

import { styled } from '@emotion/react'
const SomeStyledComponent = styled.div`
	font-size:14px;
`
<SomeStyledComponent></SomeStyledComponent>

Styled Component 생성 방법 2 : 객체

Camel Case, 스타일 값은 String Type으로 전달

import { styled } from '@emotion/react'
const SomeStyledComponent = styled('div')(() =>({
	fontSize: '14px'
}))
<SomeStyledComponent></SomeStyledComponent>

Styled Component에서 Props

const SomeStyledComponent = styled.div<{ disable: boolean }>`
	text-decoration: ${({ disable })=>( disable ? `line-through` : `none`)}
`
const SomeComponent = styled('div')<{ disable: boolean}>(({ disable })=>({
	textDecoration: disable ? `line-through` : `none`,
}))
const Component = styled(({ active, ...props }: Props타입명시) =>(
	<Link {...props} />
)) <Some타입명시>`
	font-size: 14px;
`

Gatsby에서 Markdown 파일 사용하기

Remark

Markdown을 처리하기 위한 자바스크립트 기반 파서

  • 변환된 추상 구문 트리(AST, Abstract syntax tree)를 이용하여 다른 플러그인으로 확장
  • 변환된 AST를 HTML로 변환하여 컴포넌트 출력

[Markdown] → Remark → AST(mdast) → AST 노드에 플러그인 접근(수정, 추가, 삭제) →
GraphQL 스키마 생성, 매핑 → [HTML], React 컴포넌트

Markdown 라이브러리

  • gatsby-source-filesystem
    : 변환할 파일 정보 제공 (다른 라이브러리와 연계(~-transformer, ~-images), GraphQL 연결)
  • gatsby-transformer-remark
    : HTML로 변환
  • gatsby-remark-images
    : 이미지 최적화 (반응형, loading lazy)
  • gatsby-remark-prismjs & prismjs
    : code 하이라이팅
  • gatsby-remark-smartypants
    : 문장부호 타이포그래피 가독성 좋게 자동 변환 (ex quotes ’ ” , … —)
  • gatsby-remark-autolink-headers
    : header 바로가기 링크
  • gatsby-remark-copy-linked-files
    : 사용되는 파일 static 경로로 복사 > 빌드 후에도 링크 유효
  • gatsby-remark-external-links
    : 사용되는 링크 태그 속성 지정 (target, rel)
  • gatsby-omni-font-loader
    : web font
yarn add gatsby-transformer-remark gatsby-remark-images gatsby-remark-prismjs prismjs gatsby-remark-smartypants gatsby-remark-copy-linked-files gatsby-remark-external-links
gatsby-config.js
module.exports = {
	...
	plugins: [
		{
			resolve: `gatsby-plugin-typescript`,
			options: {
				isTSX: true,
				allExtensions: true,
			},
		},
		`gatsby-plugin-emotion`,
		{
			resolve: `gatsby-source-filesystem`,
			options: {
				name: `contents`,
				path: `${__dirname}/contents`,
			},
		},
		{
			resolve: `gatsby-source-filesystem`,
			options: {
				name: `images`,
				path: `${__dirname}/static`,
			},
		},
		`gatsby-transformer-sharp`,
		`gatsby-plugin-sharp`,
		{
			resolve: `gatsby-omni-font-loader`,
			options: {
				enableListener: true,
				preconnect: [`https://cdn.jsdelivr.net/gh/orioncactus/pretendard`],
				web: [
					{
						name: `Pretendard`,
						file: `https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard-dynamic-subset.min.css`,
					},
				],
			},
		},
		{
			resolve: `gatsby-transformer-remark`,
			options: {
				plugins: [
					{
						resolve: `gatsby-remark-smartypants`,
						options: {
							dashes: `oldschool`,
						},
					},
					{
						resolve: `gatsby-remark-autolink-headers`,
						options: {
							className: `link-headers`,
							elements: [`h2`],
						},
					},
					`gatsby-remark-code-titles`,
					{
						resolve: `gatsby-remark-prismjs`,
						options: {
							classPrefix: `language-`,
						},
					},
					{
						resolve: `gatsby-remark-images`,
						options: {
							maxWidth: 768,
							quality: 100,
							withWebp: true,
						},
					},
					{
						resolve: `gatsby-remark-copy-linked-files`,
						options: {},
					},
					{
						resolve: `gatsby-remark-external-links`,
						options: { target: `_blank`, rel: `nofollow` },
					},
				],
			},
		},
		...
	],
}

code 테마 적용

gatsby-browser.js
import 'prismjs/themes/prism-tomorrow.css';

GraphQL

페이스북 쿼리언어
클라이언트가 요청한 데이터(필요한 데이터)만 가져온다

Gatsby에서 GraphQL 사용하기

GraphiQL (IDE)

View GraphiQL, an in-browser IDE, to explore your site's data and schema

	http://localhost:8000/___graphql 
  • 홈페이지의 메타데이터, 마크다운 데이터, 이미지 데이터를 Query하여 얻을 수 있다.
  • 직접 생성한 페이지(src/pages/) 또는 Gatsby가 제공한 페이지(Node API createPages)에서 Query 정의 가능하다.

GraphQL 스키마(Query 정의) → Query export(질의) → Gatsby 요청/응답 → 응답 데이터를 Props(data 키)로 전달

  • GraphQL 스키마 (데이터 구성 방식) : 데이터 사용 전 타입 정의
import { graphql } from 'gatsby'
type SomeContentProps = {  // GraphQL 스키마 정의
	data: {
		someQuery:{
			some: string
		}
	}
}
const SomeContent: FunctionComponent<SomeContentProps> = function({
	// 결과 값 : Props(data 키)
	data: {
		someQuery: {
			some
		}
	}
}) {
	return(
		<div> {some} </div>
	)
}
export default SomeContent

export const someQuery = graphql`  // Query export(질의)
	query someQuery { // 디버깅 시 로그에서 쿼리 이름(someQuery) 확인 가능
		{
			some{}
		}
	}
`

Markdown 파일에서 GraphQL (gatsby-transformer-remark 라이브러리)

  • MarkdownRemark : 파일 1개
  • allMarkdownRemark : 파일 여러개
  • file : 이미지, 파일
  • edges : 연결 (배열)
  • node : 개별 실제 데이터
  • frontmatter : 상단 메타데이터
import { graphql } from 'gatsby'
type SomePageProps = {
	data:{
		allMarkdownRemark:{
			edges: {node:{id...}}
		}
		file:{
			childrenImagesharp: string
		}
	}
}
const SomePage: FunctionComponent<SomePageProps> = function({
	data: {
		allMarkdownRemark: {edges},
		file:{
			childrenImageSharp: {gatsbyImageData},
		}
	}
}) {

	return (<div />)
}
export default SomePage

export const SomeQuery = graphql`
	query SomeQuery {
		allMarkdownRemark(sort){
			edges{
				node{
					id
					frontmatter{ title summary....}
				}
			}
		}
		file(name: {} ){
			childImageSharp{
				gatsbyImageData(width:..., height:,,,)
			}
		}
	}
`
  • 경로를 to(props)로 전달
  • 페이지의 Link 모두 찾은 후 모든 페이지(to=“경로”) Prefetch → 로딩 속도 빠름

© 2026 Choi Seohee. All Rights Reserved.