[Next.js] Github Pages 배포

 

NextJS에서는 총 5가지 방식의 랜더링 방식을 지원한다.

  • SSR(Server Side Rendering)
  • SSG(Static Site Generation)
  • CSR(Client Side Rendering)
  • Dynamic Routing
  • ISR(Incremental Static Regeneration)

Github Page는 깃헙 계정만 있으면 무료로 호스팅이 가능하다는 장점이 있지만, 정적인 페이지만 호스팅이 가능하여 Next.js에서 SSG를 제외한 나머지 랜더링 방식은 배포시에 적용이 불가능하다.

 

Vercel이나 AWS Amplify와는 다르게 Next.js를 Github Page에 정상적으로 배포하려면 몇 가지 추가적인 작업이 필요하다.

1. package.json 수정

1-1. homepage url 세팅

package.json에 배포하려는 홈페이지의 url을 homepage 속성에 입력해주면 된다.

Github Pages 기본 배포 기준으로는  "https://깃헙유저아이디.github.io/레포명"이 default url이다.

아래의 예시는 Github Pages 기본 배포를 기준으로 작성하였다.
{
  "name": "resume-template",
  // 배포하려는 홈페이지 url 추가
  "homepage": "https://hyuntaek5.github.io/resume-template",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "prebuild": "rimraf .next",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "lint:fix": "eslint --fix ./src",
    "format": "prettier --check --ignore-path .gitignore .",
    "format:fix": "prettier --write --ignore-path .gitignore .",
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook",
    "prepare": "husky install"
  },
  "dependencies": {
	...
  },
  "devDependencies": {
	...
  }
}

 

1-2. SSG 관련 export script 세팅

package.json에 scripts에 export와 관련된 스크립트를 추가한다.

preexport, export, touch, posttouch 총 4개의 스크립트를 추가하는데 각 스크립트의 목적은 다음과 같다.

preexport : export 명령어가 실행되기 이전에 기존 out 디렉토리를 제거한다.
export : next export로 SSG 정적 파일 디렉토리를 생성한다.
touch : out 디렉토리 내부에 .nojekyll 파일을 생성한다.
posttouch : touch 명령어가 실행된 이후에 out 내부의 _next 디렉토리에 .nojekyll 파일을 생성한다.
여기서 잠깐! 스크립트 앞에 pre, post를 붙이는 것만으로 어떻게 실행되는지 궁금하다면!  여기로 gogo!

touch와 posttouch 스크립트의 경우, next로 GithubPage에 배포한 사이트에서 css가 적용이 안되는 이슈를 처리하기 위해 추가한다.

 

Github Pages는 기본적으로 jekyll로 동작하기 때문에 next export를 통해 생성한 out 디렉토리를 jekyll로 처리하는데 jekyll 처리 과정에서 _next와 같은 디렉토리를 일반 리소스로 인식하지 않아 Github Page 배포시에 제외되는데 .nojekyll을 해당 디렉토리에 생성해두면 따로 jekyll 처리 과정을 거치지 않는다.

{
  "name": "resume-template",
  "homepage": "https://hyuntaek5.github.io/resume-template",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "prebuild": "rimraf .next",
    "build": "next build",
    //------- export 관련 스크립트 추가 -------//
    "preexport": "rimraf out",
    "export": "next export",
    "touch": "touch out/.nojekyll",
    "posttouch": "touch out/_next/.nojekyll",
    //------------------------------------//
    "start": "next start",
    "lint": "next lint",
    "lint:fix": "eslint --fix ./src",
    "format": "prettier --check --ignore-path .gitignore .",
    "format:fix": "prettier --write --ignore-path .gitignore .",
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook",
    "prepare": "husky install"
  },
  "dependencies": {
	...
  },
  "devDependencies": {
	...
  }
}

 

2. next.config.js 수정

2-1. basePath 설정

basePath의 default 값은 ''으로 현재 프로젝트의 루트 디렉토리를 가리키고 있다. Github Page에 배포할 때 기본 유저의 github.io 주소에 배포한다면 별 다른 문제가 없겠지만, 만약 github.io 주소 뒤에 /sub와 같이 유저 메인 주소가 아닌 다른 주소로 배포한다면 image 리소스를 가져오는 주소에서 404 에러가 발생할 수 있다. 

 

basePath가 '' 루트 디렉토리로 되어있다는 의미는 export한 정적 파일들의 이미지 리소스 주소가 "https://유저이름.github.io/이미지-파일명" 이라는 뜻이다. 해당 404 이슈를 처리하려면 basePath에 NODE_ENV를 구분하여 배포 환경에서는 Github Pages의 호스팅 디렉토리를 따라게 처리하고, 로컬에서 실행시에는 루트 디렉토리 기준으로 이미지 url을 잡게하면 된다.

/** @type {import('next').NextConfig} */

const isProduction = process.env.NODE_ENV === 'production';

const nextConfig = {
  reactStrictMode: true,
  // basePath 명시
  basePath: isProduction ? '/resume-template' : '',
};

module.exports = nextConfig;

 

2-2. images 설정

 Next.js에서 이미지를 보여줄 때, 기본적으로 next/image 패키지를 제공하여 html의 img 태그가 아닌 Image 태그를 import하여 사용할 수 있다. Image 태그를 사용하게 되면 이미지 랜더링 시에 Next에서 자동적으로 이미지 최적화를 하는데 해당 기능은 정적 파일만을 사용하는 SSG 방식에서는 불가능하므로 unoptimized 옵션을 true로 하여 Next 이미지 최적화 옵션을 꺼야한다.

/** @type {import('next').NextConfig} */

const isProduction = process.env.NODE_ENV === 'production';

const nextConfig = {
  reactStrictMode: true,
  basePath: isProduction ? '/resume-template' : '',
  // next 이미지 최적화 옵션 off
  images: {
    unoptimized: true
  }
};

module.exports = nextConfig;

3. Github Action 설정

3-1. Github Pages 배포 Action 파일 세팅 및 수정

Github Pages에 배포하고 싶은 레포지토리의 Settings에 가보면 좌측 사이드바 Code and automation 구획의 마지막에 Pages 섹션이 있는 것을 볼 수 있다.

Settings > Pages

기본적으로 Build and deployment의 Source가 Deploy from a branch로 되어있는데 Github Actions로 바꿔주면 Deploy Next.js site to Pages 워크 플로우가 생기는데 해당 yml 파일을 레포지토리의 .github/workflows/nextjs.yml과 같이 위치시킨다.

 

Github Pages가 기본 제공하는 yml 파일을 그대로 사용하게 되면 css가 반영되지 않은 사이트가 배포되는 이슈가 생기는데 1-2에서 만들어 두었던 touch 스크립트를 실행시키는 단계를 run touch와 같이 export 다음 단계에 추가한다.  

jobs:
  # Build job
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
     	...... 중략 ......
      - name: Build with Next.js
        run: ${{ steps.detect-package-manager.outputs.runner }} next build
      - name: Static HTML export with Next.js
        run: ${{ steps.detect-package-manager.outputs.runner }} next export
        // .noJekyll 파일 추가하는 단계 추가
      - name: Add noJekyll file
        run: ${{ steps.detect-package-manager.outputs.runner }} run touch
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v1
        with:
          path: ./out

 

yml 파일 수정후 Action을 돌려보면 build와 deploy 모두 정상적으로 되는 것을 확인할 수 있다.