원글: Building an Image Gallery with Next.js, Supabase, and Tailwind CSS (Lee Robinson / 2022년 3월 28일)

 

* 오역 있을 수 있습니다. 댓글이나 이메일로 말씀 부탁드립니다.

 

Vercel로 배포하기

이미지 갤러리는 Supabase로부터 가져온 이미지 목록을 Tailwind CSS를 사용하여 잘 보여주고 있습니다. 이제 우리의 Next.js 애플리케이션을 Vercel로 배포해볼까요? 배포하는 방법은 다음과 같습니다. :

1. 작성한 코드를 GitHub, GitLab, BitBucket 등의 깃 저장소에 push 해주세요.

2. 이 페이지에서 우리의 프로젝트를 Vercel로 불러와주세요.

 

import 버튼을 클릭하여 프로젝트를 Vercel로 가져와주세요!

 

3. 환경 변수를 추가해주세요.

 

 

4. Deploy 버튼을 클릭해주세요.

 

Vercel은 Next.js를 사용한 프로젝트임을 자동으로 감지하고, 배포를 위한 올바른 설정들을 사용하도록 설정할 것입니다. 그리고 마침내 애플리케이션이 swag.vercel.app과 같은 URL로 배포가 되었습니다!

 

빌드 과정에서 우리의 애플리케이션은 getStaticeProps를 통해 Supabase에 필요한 이미지에 대한 요청을 보냈고, 해당 페이지의 HTML 파일을 생성했습니다. 이 파일은 정적이며, DB를 업데이트 하더라도 변하지 않습니다.

예를 들어, 테이블에 새로운 이미지를 추가했다면, 전체 앱을 새로 빌드하지 않는 이상 배포 버전에는 해당 변경사항이 나타나지 않게 됩니다. 이를 좀 고쳐볼까요?

 

On-Demand ISR

ISR은 Next.js의 프리 렌더링 방식들 중 하나다. (관련 포스팅: https://ahnanne.tistory.com/75)

 

Next.js 12.1 버전에서는, 어떤 페이지든 업데이트 된 데이터를 배포가 이루어진 뒤에 가져올 수 있는 on-demand ISR이라는 기능이 새롭게 추가 되었습니다. ISR 방식은 빠르고 안정적이라는 이점이 있는 정적 파일을 사용하면서 동시에, 데이터가 변경되면 이를 업데이트할 수 있도록 해주는 일종의 하이브리드 방식입니다. (즉, 재배포 없이도 최신 데이터를 표시할 수 있음.)

 

현재의 ISR 방식은, 예를 들어 revalidate를 60초로 설정했다고 가정하면, 데이터 변경이 있더라도 60초가 지나지 않은 시점에는 해당 페이지에 다시 진입을 해도 업데이트된 데이터를 가져오지 않아 최신 데이터를 확인할 수 없다는 한계가 있다.
이와 달리 On-Demand ISR 방식은 요청 시에 특정 페이지에 대한 Next.js 캐시를 수동으로 제거할 수 있다고 한다.

 

그럼 이 방식을 적용해보기 위해, 우리의 images 테이블이 변경될 때 getStaticProps가 다시 호출되도록 해볼까요?

 

Supabase Function Hooks

Supabase의 Function Hooks를 통해 테이블의 어떠한 변화도 감지하여 비동기 함수를 실행시킬 수 있습니다. 예를 들어, :

- images 테이블에 새로운 행을 추가하면,

- function hook이 실행되고,

- 애플리케이션 내의 API route를 호출하여 데이터를 새로 받아온 뒤 페이지를 다시 빌드할 수 있게 됩니다.

 

이 말은, 300ms 안에 애플리케이션의 한 페이지를 즉각적으로 다시 빌드하고 이 새로운 파일을 Vercel의 Edge Network로 보낼 수 있다는 의미입니다.

 

재검증 API route 만들기

Next.js 애플리케이션 안에서 페이지를 재검증하는 API route를 만들어봅시다. 이 route는 데이터가 변경될 때 Supabase만이 페이지를 재생성할 수 있음을 보장하기 위해, Supabase 인스턴스가 전달할 비밀 쿼리 파라미터에 의해 보호됩니다. 우선 pages/api 디렉토리 안에 revalidate.ts 파일을 추가하고 다음과 같이 작성해주세요.

 

/**
 * https://www.paigeniedringhaus.com/blog/how-to-unit-test-next-js-api-routes-with-typescript
 */
import { NextApiRequest, NextApiResponse } from "next";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  // 유효한 요청인지부터 확인
  if (req.query.secret !== process.env.REVALIDATE_SECRET) {
    return res.status(401).json({ message: '유효하지 않은 토큰' });
  }

  try {
    // 페이지 재생성
    await res.unstable_revalidate('/');
    return res.json({ revalidated: true });
  } catch (err) {
    // 만약 에러가 있다면, Next.js는 기존에 성공적으로 생성되어있던 페이지를 보여줄 것이다.
    return res.status(500).send('유효성 재검증 에러');
  }
}

 

이제 이 변경사항을 배포하기 전, 아래의 새로운 환경 변수를 .env.local과 Vercel에 추가해주세요.

(그럼 이제 이것 포함해서 총 3개의 환경 변수가 존재하게 됨! 👉 NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SERVICE_KEY, REVALIDATE_SECRET)

REVALIDATE_SECRET=값

 

Function Hook 만들기

Supabase 대시보드로 가셔서, 데이터베이스를 클릭한 뒤 다음과 같이 실행해주세요.

 

1. 왼쪽 사이드바의 Database > Alpha Preview > Function Hooks를 클릭해주세요.

2. Create a new hook을 클릭해주세요. (Enable 어쩌구 버튼 있으면 그것 먼저 클릭해서 function hook 사용 활성화 해주기)

3. hook 이름은 update_images로 지어주세요.

4. images 테이블을 선택해주세요.

5. Events는 Insert, Update, Delete 모두 선택해주세요. (그래야 테이블의 삽입, 변경, 삭제 이벤트를 감지하고 웹훅이 동작할 수 있음.)

6. type of hook(훅 종류)는 HTTP Request

7. HTTP Request Method는 POST

8. HTTP Request URL은 https://{배포된 도메인}/api/revalidate (앞서 작성한 pages/api/revalidate.tshandler 함수를 호출하기 위함.)

9. HTTP Params에는 secret을 추가해주세요. (아까 환경 변수에 추가해 둔 REVALIDATE_SECRET 값과 동일해야 됨.)

10. Confirm 버튼을 눌러주세요.

 

이렇게 만든 fuction hook은 이제 활성화 되었습니다. 그럼 이제 Vercel에 재배포해주세요!

 

복사했습니다!