정적 사이트 생성(SSG), 요청 전에 만들어 두는 웹
프레임워크 문서에 나오는 SSG는 페이지의 HTML을 방문 전에 빌드로 만들어 두는 방식이다.
요청 때 조립하는 방식과 무엇이 다른지, 어떤 화면에 맞고 어디서 실패하는지 설명한다.
이 글의 목차HTML을 언제 만드느냐의 차이7
Astro나 Next.js 같은 프레임워크 문서를 읽다 보면 SSG, SSR 같은 약어가 쏟아진다.
빌드 명령을 돌리면 HTML 파일이 가득 든 폴더가 생기고, 그 폴더를 그대로 올리면 된다는 안내도 나온다.
이 HTML을 언제, 무엇이 만들었는지 알려면 웹페이지가 만들어지는 시점부터 봐야 한다.
HTML을 언제 만드느냐의 차이
브라우저가 받아 가는 것은 결국 HTML 문서다.
이 문서를 만드는 시점은 크게 두 가지다.
하나는 요청이 들어온 뒤에 만드는 방식이다.
서버가 데이터베이스에서 글을 읽어 틀에 채우고, 완성된 HTML을 그 자리에서 돌려준다.
이것을 서버 측 렌더링, 줄여서 SSR이라고 부른다.
다른 하나는 요청이 오기 전에 미리 만들어 두는 방식이다.
배포 전에 페이지마다 HTML 파일을 만들어 두고, 요청이 오면 그 파일을 그대로 보낸다.
미리 만드는 이 작업을 빌드라고 하고, 사이트 전체를 빌드로 만들어 두는 방식을 정적 사이트 생성(SSG)이라고 한다.
이렇게 빌드 때 한 번 만든 HTML을 이후의 모든 요청에 그대로 다시 쓴다.
방문자가 몰리면 바빠지는 곳
요청 때 만드는 방식에서는 방문자마다 같은 조립이 되풀이된다.
읽는 사람이 늘면 서버와 데이터베이스가 하는 일도 그만큼 늘어난다.
이 경로의 어느 하나가 멈추면 어제 써 둔 글까지 함께 안 보인다.
글을 읽기만 하는 방문자도 데이터베이스가 살아 있어야 글을 볼 수 있기 때문이다.
미리 만들어 두는 방식에서는 요청마다 계산할 것이 없다.
완성된 파일을 보내기만 하면 되니, CDN에 올려 두고 방문자와 가까운 곳에서 바로 내보내기도 쉽다.
같은 데이터베이스의 글이라도 방문자에게 보이는지는 HTML을 만드는 시점과 데이터베이스의 상태에 따라 달라진다.
- 요청 뒤 서버의 일데이터베이스에서 글을 읽어 HTML 조립
- 데이터베이스요청마다 조회에 응답
어제 쓴 글
보임요청마다 새로 조립
오늘 새로 쓴 글
보임저장하면 다음 요청부터
- 요청 뒤 서버의 일글을 읽지 못해 조립 실패
- 데이터베이스응답 없음
어제 쓴 글
안 보임오류 화면
오늘 새로 쓴 글
안 보임데이터베이스가 멈춤
- 요청 뒤 서버의 일빌드 때 만든 HTML 파일 전달
- 데이터베이스빌드할 때만 읽힘
어제 쓴 글
보임이미 만든 파일
오늘 새로 쓴 글
다음 빌드 뒤 보임빌드와 배포를 다시 거침
- 요청 뒤 서버의 일빌드 때 만든 HTML 파일 전달
- 데이터베이스멈춤 · 요청 때는 쓰지 않음
어제 쓴 글
보임이미 만든 파일
오늘 새로 쓴 글
안 보임빌드가 글을 읽지 못해 실패
요청 때 HTML을 만드는 방식은 데이터베이스가 멈추면 어제 쓴 글도 보여 주지 못한다. 빌드 때 만들어 둔 방식은 이미 만든 파일을 그대로 보내고, 데이터베이스가 돌아올 때까지 새 빌드만 실패한다.
요청마다 데이터베이스에서 글을 읽어 화면을 조립한다. 새 글도 저장하면 다음 요청부터 보인다.
빌드도 같은 데이터베이스에서 글을 읽는다고 가정한 예시다. 캐시와 CDN, 데이터베이스 복제본은 없다고 보았다.
캐시와는 무엇이 다른가
여기서 캐시와 헷갈리기 쉽다.
캐시는 이미 만든 결과를 저장해 두었다가 다음 요청에 다시 쓰는 방법이다.
첫 요청 때 채우기도 하고, 미리 채워 두기도 한다.
정적 사이트 생성은 페이지를 만드는 시점 자체를 배포 전으로 옮기는 방법이다.
하는 일이 다르니 둘을 함께 쓸 수 있다.
빌드로 만든 HTML을 CDN에 캐시해 두는 식이다.
웹이 매번 조립하게 된 내력
초기 웹 서버는 디스크에 있는 파일을 그대로 돌려줬다.
방문자마다 다른 화면을 주려면, 요청이 올 때마다 프로그램을 실행하고 그 출력을 응답으로 보내는 방법이 필요했다.
1993년부터 웹에서 쓰인 CGI가 그 규약이다.
PHP도 처음에는 Rasmus Lerdorf가 자기 온라인 이력서의 방문자를 세려고 C로 짠 CGI 프로그램 묶음이었다.
블로그 도구도 이 길을 따랐다.
WordPress는 지금도 PHP와 MySQL 같은 데이터베이스가 있어야 돌아간다.
그러다 계속 손봐야 하는 동적 사이트 대신 정적 사이트로 돌아가는 도구가 나왔다.
Jekyll은 Git 저장소에 둔 텍스트 글을 읽어 완성된 HTML 묶음을 만들어 준다.
파일을 그대로 내보낸다는 점은 초기 웹과 같다.
다만 그 HTML을 이제는 사람이 손으로 쓰지 않는다.
이런 방식을 JAMstack이라고 부르기도 한다.
자바스크립트, API, 마크업의 머리글자를 딴 이름으로, 페이지를 보여 줄 때마다 사이트를 만드는 백엔드를 직접 운영하지 않는다는 뜻이 담겨 있다.
미리 만들어 두면 포기하는 것
정적 방식은 빌드할 때의 데이터로 화면을 굳힌다.
빌드 뒤에 바뀐 내용은 다시 빌드하기 전까지 보이지 않는다.
오타 하나를 고쳐도 빌드와 배포를 다시 거쳐야 한다.
사람마다 다른 화면도 미리 만들 수 없다.
주문 내역이나 장바구니처럼 로그인한 사람에 따라 달라지는 내용은 요청이 와야 알 수 있다.
빌드 자체가 실패할 수도 있다.
이때 새 글은 올라가지 않지만, 배포 방식을 잘 정해 두면 이미 올라가 있던 파일은 그대로 남는다.
글이 수천 개라면 문제가 하나 더 생긴다.
고칠 때마다 전부 다시 만들면 빌드가 길어진다.
Next.js의 ISR은 사이트 전체를 다시 빌드하지 않고 페이지를 정해진 시간마다 새로 만들게 해 준다.
ISR을 쓴다고 해서 파일만 올려 두는 정적 호스팅에 그대로 올릴 수 있는 것은 아니다.
ISR은 Next.js 서버가 돌아가야 쓸 수 있고, 파일만 내보내는 정적 내보내기에서는 지원되지 않는다.
정해진 시간이 지난 뒤 처음 온 방문자도 일단 이전 페이지를 받는다.
새 페이지는 그 요청을 계기로 뒤에서 만들어지고, 다 만들어진 뒤부터 다음 방문자에게 나간다.
새로 만들다가 실패하면 이전 페이지가 그대로 나가고, 다음 요청 때 다시 만든다.
화면마다 방식을 고른다
사이트 전체를 꼭 한 방식으로 정할 필요는 없다.
Astro는 기본으로 모든 페이지를 빌드할 때 만든다.
로그인한 사용자의 계정 정보를 보여 주는 페이지처럼 필요한 곳만 골라 요청 시 렌더링으로 바꿀 수 있다.
한 화면 안에서 나눌 수도 있다.
모두에게 같은 목록과 본문은 빌드로 만들어 두고, 로그인 상태나 장바구니 개수처럼 사람마다 다른 조각만 페이지가 뜬 뒤 브라우저가 따로 받아 와 채우는 식이다.
방식을 고를 때는 화면마다 그 결과를 모든 방문자에게 똑같이 줘도 되는지를 본다.
| 화면의 성격 | 잘 맞는 방식 | 그 방식이 실패하면 |
|---|---|---|
| 누가 봐도 같은 글과 문서 | 미리 만든다 | 빌드가 깨져 새 내용이 안 올라간다 |
| 로그인한 사람마다 다른 장바구니 | 요청 때 만든다 | 서버가 멈추면 화면이 안 뜬다 |
| 대부분 같고 일부만 다른 화면 | 뼈대만 미리 만들고 나머지는 나중에 채운다 | 채우는 쪽만 비어 화면 일부가 빈다 |
정적 사이트를 운영할 때
빌드는 글이나 코드를 저장소에 올릴 때마다 자동으로 돌게 해 두면 편하다.
지속적 배포를 붙여 두면 빌드가 성공했을 때만 새 파일이 공개된다.
올릴 때는 새 파일 묶음을 다 올린 뒤 한 번에 바꿔 끼우는 방식이 안전하다.
그래야 빌드나 업로드가 중간에 실패해도 방문자는 이전 버전을 온전히 본다.