본문 바로가기

Next.js

Next.js 13-2 Deploying Static Exports

  Next.js는 정적 사이트 또는 SPA(Single-Page Application)로 시작한 다음 나중에 선택적으로 서버가 필요한 기능을 사용하도록 업그레이드할 수 있다.

  next build를 실행할 때 Next.js는 경로별로 HTML 파일을 생성한다. 엄격한 SPA를 개별 HTML 파일로 나누면, Next.js는 클라이언트 측에서 불필요한 JavaScript 코드를 로드하지 않도록 하여 번들 크기를 줄이고 더 빠른 페이지 로드를 가능하게 한다.

  Next.js는 이 정적 내보내기를 지원하므로 HTML/CSS/JS 정적 자산을 제공할 수 있는 모든 웹 서버에 배포하고 호스팅 할 수 있다.

 

  • Configuration

  정적 내보내기를 활성화하려면 내부에서 출력 모드를 변경하면 된다.

// next.config.js

/**
  * @type {import('next').NextConfig}
  */
  const nextConfig = {
    output: 'export',
    // Optional: Add a railing slash to all paths '/about' -> '/about/'
    // trailingSlash: true,
    // Optional: Change the output directory 'out' -> 'dist'
    // distDir: 'dist',
}
  
module.exports = nextConfig

  next build를 실행한 후 Next.js는 애플리케이션의 HTML/CSS/JS 자산을 포함하는 out 폴더를 생성한다.

 

  • Supported Features

Server Components

  정적 내보내기를 생성하기 위해 next build를 실행하면 기존의 정적 사이트 생성과 유사하게 앱 디렉토리 내에서 사용되는 서버 컴포넌트 빌드 중에 실행된다.

  결과 컴포넌트는 초기 페이지 로드를 위한 정적 HTML과 경로 간 클라이언트탐색을 위한 정적 페이로드로 렌더링 된다. 동적 서버 기능을 사용하지 않는 한 내보내기를 사용할 때 서버 컴포넌트를 변경할 필요가 없다.

// app/page.tsx

export default async function Page() {
  // This fetch will run on the server during 'next build'
  const res = awiat fetch('https://api.example.com/...')
  const data = await res.json()
  
  return <main>...</main>
}

 

 

Client Components

  클라이언트에서 데이터 가져오기를 수행하려는 경우 SWR과 함께 클라이언트 컴포넌트를 사용하여 요청을 중복 제거할 수 있다.

// app/other/page.tsx

'use client'

import useSWR from 'swr'

const fetcher = (url: string) => fetch(url).then((r) => r.json())

export default function Page() {
  const { data, error } = useSWR(
    'https://jsonplaceholder.typicode.com/posts/1',
    fetcher
  )
  if (error) return 'Failed to load'
  if (!data) return 'Loading...'
  
  return data.title
}

  경로 전환은 클라이언트 측에서 발생하므로 기존 SPA처럼 작동한다. 예를 들어 다음 인덱스 경로를 사용하면 클라이언트의 다른 게시물로 이동할 수 있다.

// app/page.tsx

import Link from 'next/link'

export default function Page() {
  return (
    <>
      <h1>Index Page</h1>
      <hr />
      <ul>
        <li>
          <Link href="/post/1">Post 1</Link>
        </li>
        <li>
          <Link href="/post/2">Post 2</Link>
        </li>
      </ul>
    </>
  )
}

 

 

Image Optimization

  next/image를 통한 이미지 최적화는 next.config.js에서 사용자 정의 이미지 로더를 정의하여 정적 내보내기와 함께 사용할 수 있다. 예를 들어 Cloudinary와 같은 서비스로 이미지를 최적화할 수 있다.

// next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',
  images: {
    loader: 'custom',
    loaderFile: './app/image.ts'
  },
}

module.exports = nextConfig

  이 사용자 정의 로드는 원격 소스에서 이미지를 가져오는 방법을 정의한다. 예를 들어 다음 로더는 Cloudinary에 대한 URL을 구성한다.

// app/image.ts

export default function cloudinaryLoader({
  src,
  width,
  quality,
}: {
  src: string
  width: number
  quality?: number
}) {
  const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
  return `https://res.cloudinary.com/demo/image/upload/${params.join(
    ','
  )}${src}`
}

  그런 다음 애플리케이션에서 next/image를 사용하여 Cloudinary에서 이미지에 대한 상대 경로를 정의할 수 있다.

// app/page.tsx

import Image from 'next/image'

export default function Page() {
  return <Image alt="turtles" src="/turtles.jpg" width={300} height={300} />
}

 

 

Route Handlers

  경로 처리기는 next build를 실행할 때 정적 응답을 렌더링 한다. GET HTTP 동사만 지원된다. 이는 동적 또는 정적 데이터에서 정적 HTML, JSON, TXT 또는 기타 파일을 생성하는 데 사용할 수 있다.

// app/data.json/route.ts

import { NextResponse } from 'next/server'

export async function GET() {
  return NextResponse.json({ name: 'Lee' })
}

  위 파일 app/data.json/route.ts는 다음 빌드 중 정적 파일로 렌더링 되어 { name: 'Lee' }를 포함하는 data.json을 생성한다. 들어오는 요청에서 동적 값을 읽어야 하는 경우 정적 내보내기를 사용할 수 없다.

 

Browser APIs

  클라이언트 컴포넌트는 다음 빌드 중에 HTML로 사전 렌더링된다. window, localStorage, navigator와 같은 Web API는 서버에서 사용할 수 없기 때문에 이러한 API는 브라우저에서 실행할 때만 안전하게 액세스해야 한다.

'use client';

import { useEffect } from 'react';

export default function ClientComponent() {
  useEffect(() => {
    // You now have access to 'window'
    console.log(window.innerHeight);
  }, [])
  
  return ...;
}

 

  • Unsupported Features

  정적 내보내기 output 모드를 활성화하면 앱 내부의 모든 경로가 다음 경로 세그먼트 구성에 옵트인 된다.

export const dynamic = 'error'

  이 구성에서는 런타임 서버가 없기 때문에 헤더나 쿠키와 같은 서버 기능을 사용하려고 하면 애플리케이션에서 오류가 발생한다. 이를 통해 로컬 개발이 정적 내보내기와 동일한 동작을 일치하도록 한다. 서버 기능을 사용해야 하는 경우 정적 내보내기를 사용할 수 없다.

  다음 추가 동적 기능은 정적 내보내기에서 지원되지 않는다.

rewrites in next.config.js
redirects in next.config.js
headers in next.config.js
middleware
Incremental Static Regeneration

 

  • Deploying

  정적 내보내기를 사용하면 HTML/CSS/JS 정적 자산을 제공할 수 있는 모든 웹 서버에서 Next.js를 배포하고 호스팅 할 수 있다. 다음 빌드를 실행할 때 Next.js는 out 폴더로 정적 내보내기를 생성한다. 더 이상 다음 내보내기를 사용할 필요가 없다. 예를 들어 다음과 같은 경로가 있다고 가정한다. /, /blog/[i]

  next build를 실행한 후 Next.js는 다음 파일을 생성한다.

/out/index.html
/out/404.html
/out/blog/post-1.html
/out/blog/post-2.html

  Nginx와 같은 정적 호스트를 사용하는 경우 들어오는 요청에서 올바른 파일로 다시 쓰기를 구성할 수 있다.

// nginx.conf

server {
  listen 80;
  server_name acme.com;
  
  root /var/www;
  
  location / {
  	try_files /out/index.html =404;
  }
  
  location /blog/ {
  	rewrite ^/blog/(.*)$ /out/blog/$1.html break;
    
  error_page 404 /out/404.html;
  location = /404.html {
  	internal;
  }
}