성능 최적화와 배포까지 마무리하기
개발 서버와 프로덕션 빌드는 다르다
지금까지는 대부분 npm run dev로 앱을 실행했습니다. 개발 서버는 빠른 수정에 맞춰져 있습니다. 파일을 저장하면 브라우저가 곧바로 바뀌고, 오류도 개발자가 보기 좋게 표시됩니다.
하지만 실제 서비스는 다릅니다. 사용자는 개발 서버가 아니라 최적화된 결과물을 받습니다. 그래서 배포 전에 반드시 프로덕션 빌드를 확인해야 합니다.
npm run build
npm run previewnpm run build는 SvelteKit 앱을 배포 가능한 형태로 만듭니다. 이 과정에서 Svelte 컴포넌트는 브라우저가 실행할 JavaScript와 CSS로 변환되고, 사용하지 않는 코드가 제거되며, 필요하다면 미리 만들 수 있는 페이지를 HTML로 생성합니다. 마지막에는 adapter가 배포 대상에 맞는 출력물을 만듭니다.
npm run preview는 빌드된 결과를 로컬에서 확인하는 명령입니다. 개발 서버처럼 빠른 저장 반영을 위한 환경이 아니라, 실제 배포 결과에 가까운 화면을 확인하는 용도입니다. 다만 preview는 로컬 Node 환경에서 실행되기 때문에 Vercel, Netlify, Cloudflare 같은 플랫폼의 세부 동작까지 완전히 똑같이 재현하지는 않습니다.3 그래도 빌드 결과가 기본적으로 잘 동작하는지 확인하는 단계로는 꼭 필요합니다.
개발 중에는 잘 보이던 화면이 빌드 후 깨질 수 있습니다. 대표적인 이유는 다음과 같습니다.
서버에서도 실행되는 코드에서
window,document,localStorage를 바로 사용한 경우환경 변수를 공개용과 비공개용으로 구분하지 않은 경우
빌드 시점에 실행되면 안 되는 초기화 코드가 그대로 실행된 경우
빌드 시점에 필요한 데이터가 준비되지 않은 경우
특정 배포 환경에 맞는 adapter 설정이 빠진 경우
따라서 배포 전 루틴은 단순합니다.
npm run check
npm run test
npm run build
npm run preview앞 장에서 배운 타입 검사와 테스트를 먼저 실행하고, 마지막에 빌드와 preview로 실제 결과를 확인합니다. 이 순서가 습관이 되면 배포 직전에 발견되는 문제를 줄일 수 있습니다.
AI 생성 이미지
렌더링 전략은 배포 방식까지 바꾼다
SvelteKit 앱을 배포할 때 가장 먼저 생각할 질문은 "이 페이지를 언제 HTML로 만들 것인가?"입니다. 답은 크게 세 가지입니다.
SSR: 요청이 들어올 때 서버에서 HTML을 만든다.
SSG: 빌드할 때 미리 HTML을 만든다.
SPA: 처음에는 빈 틀을 보내고 브라우저에서 화면을 만든다.
SSR: 서버에서 먼저 그리는 방식
SvelteKit은 기본적으로 SSR이 켜져 있습니다. 사용자가 페이지에 처음 접속하면 서버가 HTML을 만들어 보내고, 브라우저는 그 HTML을 먼저 보여 줍니다. 이후 JavaScript가 붙으면서 버튼 클릭, 폼 입력, 페이지 이동 같은 동작이 가능해집니다. 이 과정을 hydration이라고 부릅니다.
SSR은 블로그, 쇼핑몰, 검색 결과, 상세 페이지처럼 첫 화면이 빨리 보여야 하거나 검색 엔진에 내용이 잘 읽혀야 하는 페이지에 잘 맞습니다.
예를 들어 상품 상세 페이지가 있다고 합시다.
/products/1
/products/2
/products/3사용자가 /products/1에 접속했을 때 서버가 상품 이름, 가격, 설명이 들어간 HTML을 바로 보내면 사용자는 빠르게 내용을 볼 수 있습니다. 검색 엔진도 이 HTML을 읽기 쉽습니다.
다만 SSR은 실행할 서버가 필요합니다. 꼭 전통적인 서버 한 대일 필요는 없지만, Vercel Functions, Netlify Functions, Cloudflare Workers, Node 서버처럼 요청을 받아 코드를 실행할 환경이 있어야 합니다.
SSG: 미리 만들어 두는 방식
SSG는 Static Site Generation의 줄임말입니다. 빌드할 때 HTML을 미리 만들어 두고, 배포 후에는 정적 파일처럼 제공합니다.
SvelteKit에서는 라우트의 +page.ts, +layout.ts 같은 모듈에서 다음처럼 설정할 수 있습니다.
export const prerender = true;문서 사이트, 소개 페이지, 회사 홈페이지, 자주 바뀌지 않는 블로그 글처럼 데이터가 고정적인 페이지에 적합합니다. 서버 실행 환경이 없어도 CDN에서 빠르게 제공할 수 있다는 장점이 있습니다.
하지만 빌드 후 데이터가 바뀌어도 이미 만들어진 HTML은 자동으로 바뀌지 않습니다. 새 글이 추가되거나 가격이 바뀌면 다시 빌드하고 배포해야 합니다. 실시간성이 필요한 대시보드나 로그인 사용자별 화면에는 맞지 않는 경우가 많습니다.
SPA: 브라우저에서 그리는 방식
SPA는 Single Page Application입니다. 서버는 거의 빈 HTML과 JavaScript 파일을 보내고, 실제 화면은 브라우저에서 만들어집니다.
SvelteKit에서 특정 구간을 SPA처럼 만들고 싶다면 레이아웃이나 페이지의 옵션에서 SSR을 끌 수 있습니다.
export const ssr = false;완전히 정적 호스팅에 올리면서 브라우저에서만 동작하는 앱을 만들 때 사용할 수 있습니다. 관리자 도구, 로그인 뒤에만 접근하는 내부 서비스, 검색 노출이 중요하지 않은 앱에 어울립니다.
대신 첫 화면이 SSR보다 늦게 보일 수 있습니다. 사용자는 JavaScript가 다운로드되고 실행된 뒤에야 주요 내용을 보게 됩니다. 검색 엔진 최적화도 SSR이나 SSG보다 불리할 수 있습니다.
정리하면 다음 기준으로 고르면 됩니다.
| 전략 | 어울리는 경우 | 주의할 점 |
|---|---|---|
| SSR | 상품 상세, 검색 결과, 사용자별 페이지 | 서버 실행 환경 필요 |
| SSG | 문서, 블로그, 소개 페이지 | 데이터 변경 시 재빌드 필요 |
| SPA | 관리자 도구, 내부 앱, 정적 호스팅 앱 | 초기 로딩과 SEO에 불리할 수 있음 |
adapter는 배포 환경에 맞는 출력 방식을 정한다
SvelteKit에서 adapter는 빌드 결과를 특정 배포 환경에 맞게 바꾸는 역할을 합니다. 같은 SvelteKit 앱이라도 Vercel에 올릴 때, Netlify에 올릴 때, Node 서버에서 실행할 때 필요한 출력 방식이 다릅니다.
처음 만든 프로젝트에는 보통 adapter-auto가 설정되어 있습니다.
// svelte.config.js
import adapter from '@sveltejs/adapter-auto';
export default {
kit: {
adapter: adapter()
}
};adapter-auto는 배포 플랫폼을 감지해 적절한 adapter를 선택하려고 합니다. Vercel이나 Netlify처럼 SvelteKit을 잘 지원하는 플랫폼에 처음 배포할 때는 편합니다.
하지만 배포 대상이 명확해지면 adapter를 직접 고르는 편이 좋습니다. 설정 파일만 봐도 "이 앱은 어디에 배포되는가?"를 알 수 있고, 플랫폼별 옵션도 명확하게 다룰 수 있기 때문입니다.
정적 사이트라면 adapter-static
모든 페이지를 정적으로 만들 수 있다면 adapter-static을 사용할 수 있습니다.
npm install -D @sveltejs/adapter-static// svelte.config.js
import adapter from '@sveltejs/adapter-static';
export default {
kit: {
adapter: adapter()
}
};이 방식은 GitHub Pages, 정적 파일 서버, CDN 중심 배포에 잘 맞습니다. 단, 서버에서 매 요청마다 데이터를 가져오는 페이지나 서버 form action이 필요한 기능은 그대로 사용할 수 없습니다.
adapter-static을 사용할 때는 중요한 조건이 있습니다. 기본적으로 모든 페이지와 엔드포인트가 정적으로 만들어질 수 있어야 합니다. 그렇지 않다면 fallback 파일을 지정해 SPA처럼 처리해야 합니다.4
SPA로 배포해야 한다면 fallback 파일을 지정하는 경우가 많습니다.
adapter({
fallback: '200.html'
})fallback 파일 이름은 배포 환경에 따라 달라질 수 있습니다. 어떤 곳은 200.html을 쓰고, GitHub Pages처럼 없는 주소를 특정 파일로 돌려야 하는 환경에서는 404.html을 쓰기도 합니다. 중요한 것은 /products/1 같은 주소로 바로 접속했을 때 정적 서버가 fallback HTML을 돌려주고, 이후 브라우저의 클라이언트 라우터가 실제 화면을 처리하게 만드는 것입니다.
다만 이 방식은 SSR이나 SSG보다 초기 로딩과 SEO에 불리할 수 있습니다. 그래서 정말 SPA가 필요한 상황인지, 아니면 주요 페이지는 prerender하고 나머지만 다른 방식으로 처리할 수 있는지 먼저 생각해 보는 것이 좋습니다.
직접 Node 서버에서 실행한다면 adapter-node
직접 서버를 운영하거나 Docker, VPS, 일부 클라우드 런타임에서 실행한다면 adapter-node가 잘 맞습니다.
npm install -D @sveltejs/adapter-node// svelte.config.js
import adapter from '@sveltejs/adapter-node';
export default {
kit: {
adapter: adapter()
}
};빌드 후에는 보통 다음처럼 실행합니다.
npm run build
node buildpackage.json에 시작 명령을 추가해 둘 수도 있습니다.
{
"scripts": {
"build": "vite build",
"start": "node build"
}
}Node 배포는 자유도가 높습니다. 직접 로그, 프로세스 관리, 리버스 프록시, 환경 변수, 데이터베이스 연결을 통제할 수 있습니다. 대신 서버 운영 책임도 함께 생깁니다. 특히 production에서는 .env 파일이 자동으로 로드된다고 가정하지 말고, 배포 환경의 환경 변수 설정 방식이나 dotenv, Node의 --env-file 옵션 등을 확인해야 합니다.
번들 크기를 관리하는 기본 습관
성능 최적화는 특별한 기술 하나로 끝나지 않습니다. 사용자가 내려받는 파일을 줄이고, 필요한 순간에 필요한 코드만 실행하게 만드는 작은 선택의 합입니다.
가장 먼저 볼 것은 이미지입니다. 웹 페이지에서 가장 큰 파일은 JavaScript보다 이미지인 경우가 많습니다.
원본 사진을 그대로 넣지 않는다.
표시 크기에 맞게 줄인다.
가능하면 WebP, AVIF 같은 현대적인 포맷을 사용한다.
목록 화면에서는 작은 썸네일을 사용한다.
화면 아래 이미지는 lazy loading을 고려한다.
<img
src="/products/chair.webp"
alt="나무 의자"
loading="lazy"
width="400"
height="300"
/>width와 height를 지정하면 이미지가 늦게 로드되어도 레이아웃이 덜 흔들립니다. 사용자는 버튼이나 글이 갑자기 밀리는 경험을 덜 하게 됩니다.
다음은 코드 분할입니다. SvelteKit은 라우트 단위로 필요한 코드를 나누는 구조를 기본적으로 갖고 있습니다. 사용자가 /cart에 들어오지 않았는데 장바구니 페이지의 모든 코드를 첫 화면에서 받을 필요는 없습니다.
하지만 개발자가 큰 라이브러리를 무심코 공통 레이아웃에 넣으면 모든 페이지가 그 비용을 치를 수 있습니다. 예를 들어 차트 라이브러리가 특정 통계 페이지에서만 필요하다면 앱 전체 레이아웃이 아니라 해당 페이지에서만 불러오는 편이 좋습니다.
import Chart from '큰-차트-라이브러리';이 코드가 최상위 레이아웃에 있으면 앱 전체 번들에 영향을 줄 수 있습니다. 정말 필요한 페이지 안으로 옮기거나, 필요한 순간에 동적으로 불러오는 방식을 검토합니다.
예를 들어 사용자가 버튼을 눌러 차트를 열 때만 필요하다면 다음처럼 동적 import를 사용할 수도 있습니다.
const chartModule = await import('큰-차트-라이브러리');물론 모든 import를 무조건 동적으로 바꾸라는 뜻은 아닙니다. 자주 쓰는 코드는 일반 import가 더 단순합니다. 핵심은 "이 코드가 첫 화면에 꼭 필요한가?"를 한 번 확인하는 것입니다.
마지막은 의존성 정리입니다.
npm uninstall 사용하지-않는-패키지작은 유틸 함수 하나 때문에 큰 라이브러리를 추가하지 않는 것도 중요합니다. 날짜 포맷, 숫자 포맷, 간단한 배열 처리처럼 브라우저 기본 API나 짧은 함수로 해결할 수 있는 일은 먼저 직접 해결해 봅니다.
대표 배포 대상별 준비 사항
배포 플랫폼마다 버튼 이름과 화면은 다르지만 준비할 내용은 비슷합니다.
Vercel
Vercel은 SvelteKit 배포 경험이 좋은 플랫폼입니다. GitHub 저장소를 연결하면 빌드 명령을 자동으로 감지하는 경우가 많습니다.
확인할 것은 다음입니다.
빌드 명령:
npm run build환경 변수 등록 여부
SSR이 필요한 페이지가 있는지
adapter-auto를 그대로 쓸지, Vercel adapter를 명시할지
처음에는 adapter-auto로 시작해도 충분합니다. 팀 프로젝트나 복잡한 서버 기능이 생기면 플랫폼 전용 adapter를 명시해 배포 동작을 더 분명히 만드는 것이 좋습니다.
Netlify
Netlify는 SvelteKit SSR과 엔드포인트를 Netlify Functions로 배포할 수 있습니다. Netlify 공식 가이드는 SvelteKit 프로젝트에서 @sveltejs/adapter-netlify 사용을 권장하며, 일반적인 빌드 명령은 npm run build, 게시 디렉터리는 build로 둡니다.1
정적 사이트라면 adapter-static도 사용할 수 있습니다. 반대로 서버 action, API 엔드포인트, SSR이 필요하다면 Netlify adapter를 사용하는 편이 자연스럽습니다. Edge Functions를 사용할 때는 일반 Node 환경과 다른 런타임 제약이 있으므로, 사용하는 패키지가 그 환경에서 동작하는지도 함께 확인해야 합니다.
Cloudflare
Cloudflare Pages와 Workers 계열은 전 세계 edge 환경에서 실행하는 데 강점이 있습니다. 사용자와 가까운 위치에서 응답할 수 있어 지연 시간을 줄이는 데 유리합니다.
다만 Node 서버와 완전히 같은 환경은 아닙니다. Node 전용 API나 특정 패키지가 edge 런타임에서 동작하지 않을 수 있습니다. Cloudflare에 배포할 계획이라면 @sveltejs/adapter-cloudflare를 검토하고, 서버 코드에서 사용하는 라이브러리가 Workers 환경을 지원하는지 확인해야 합니다.
직접 운영하는 Node 서버
VPS, 사내 서버, Docker 환경처럼 직접 Node 프로세스를 실행할 수 있다면 adapter-node가 기준입니다. 일부 배포 가이드도 Node 기반 배포에서 @sveltejs/adapter-node를 설치하고 start 스크립트로 node build를 지정하는 흐름을 안내합니다.2
직접 운영할 때는 앱 코드만 보면 부족합니다.
NODE_ENV=production설정PORT,HOST,ORIGIN같은 실행 환경 변수 확인비공개 환경 변수 관리
HTTPS 설정
프로세스 재시작 도구 사용
로그 수집
데이터베이스 연결 정보 보호
이 부분은 프론트엔드 코드 바깥의 운영 영역입니다. 작게 시작한다면 Vercel, Netlify 같은 플랫폼을 쓰는 편이 단순합니다. 운영 제어가 필요해질 때 Node 서버 배포로 확장해도 늦지 않습니다.
배포 전 마지막 체크리스트
배포는 "코드를 올리는 일"이 아니라 "사용자가 안정적으로 접근할 수 있는 상태를 만드는 일"입니다. 마지막으로 다음 항목을 확인합니다.
npm run check가 통과하는가?주요 테스트가 통과하는가?
npm run build가 실패 없이 끝나는가?npm run preview에서 주요 화면과 폼이 동작하는가?환경 변수를 배포 플랫폼에 등록했는가?
비공개 키를 클라이언트 코드에 넣지 않았는가?
렌더링 전략과 adapter가 배포 환경에 맞는가?
정적 배포라면 모든 경로가 prerender되거나 fallback으로 처리되는가?
이미지 크기와 불필요한 의존성을 점검했는가?
없는 주소, 오류 화면, 로딩 상태를 확인했는가?
이 과정을 거치면 Svelte 개발의 한 사이클이 완성됩니다. 컴포넌트를 만들고, 상태를 연결하고, 데이터를 불러오고, 서버 기능을 붙이고, 테스트하고, 빌드하고, 배포합니다.
처음부터 완벽한 최적화를 목표로 할 필요는 없습니다. 먼저 제대로 빌드되고 배포되는 앱을 만드세요. 그다음 실제 사용자가 느끼는 느린 지점, 큰 이미지, 무거운 페이지, 반복되는 서버 요청을 하나씩 줄이면 됩니다. 성능 최적화는 추측보다 측정과 반복에 가까운 작업입니다.
참고
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.