들어가며
Vue, React, Svelte 등 SPA 프레임워크는 이미 많은 기능을 추상화해 제공하지만,
그 근본 원리를 이해하기 위해서는 프레임워크 없이 직접 SPA(Single Page Application)를 구현해보는 것이 큰 도움이 됩니다.
이 글에서는 바닐라 JavaScript만을 사용해:
- 기본 라우팅 처리
- 동적 렌더링 구조
- 간단한 상태 관리 구조 을 직접 구성해보는 실전 예제를 소개합니다.
1. SPA란?
페이지 전체를 새로고침하지 않고, JavaScript로 동적으로 콘텐츠를 교체하는 방식의 웹 앱
특징
- 브라우저가 최초에 HTML/CSS/JS를 모두 받고 이후에는 JS가 동작 주도
- URL 변화는 pushState/popState로 관리됨
2. HTML 기본 구조
<body>
<nav>
<a href="/" data-link>Home</a>
<a href="/about" data-link>About</a>
</nav>
<div id="app"></div>
<script src="app.js" type="module"></script>
</body>
- data-link 속성은 라우터가 제어할 링크임을 표시
- #app은 페이지 내용을 동적으로 렌더링할 영역
3. 라우터 기본 구현 (hash 없이 pushState 기반)
function navigateTo(url) {
history.pushState(null, null, url);
router();
}
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if (e.target.matches("[data-link]")) {
e.preventDefault();
navigateTo(e.target.href);
}
});
window.addEventListener("popstate", router);
router();
});
- navigateTo()는 브라우저 주소만 바꾸고 실제 이동은 하지 않음
- router() 함수에서 URL에 따라 콘텐츠 렌더링함
4. 라우터 매핑과 렌더링 함수
const routes = [
{ path: "/", view: () => "<h1>Home Page</h1>" },
{ path: "/about", view: () => "<h1>About Page</h1>" },
];
function router() {
const potentialMatch = routes.find(r => r.path === location.pathname);
const view = potentialMatch ? potentialMatch.view : () => "<h1>404</h1>";
document.querySelector("#app").innerHTML = view();
}
5. 동적 파라미터 지원 (예: /post/:id)
// 라우팅 규칙에 정규표현식 사용
// /post/:id → /^\/post\/([^\/]+)$/
- 동적으로 path 파싱하여 URL에서 변수 추출 가능
- 정규표현식 기반 간단한 라우터 확장도 가능함
6. 상태 관리 예시 (간단한 전역 객체 활용)
const store = {
state: {
count: 0
},
increment() {
this.state.count++;
render();
}
};
function render() {
document.querySelector("#app").innerHTML = `
<h1>Count: ${store.state.count}</h1>
<button id="inc">+</button>
`;
document.querySelector("#inc").addEventListener("click", () => store.increment());
}
마치며
프레임워크 없이 구현한 SPA는 최소한의 구조만으로도 작동 원리를 이해하는 데 큰 도움이 됩니다.
- pushState와 popstate를 활용한 클라이언트 라우팅
- render 함수로 컴포넌트처럼 구성하는 방식
- 간단한 전역 상태 관리 구조
📂 다음 글에서는:
- 템플릿 렌더링 개선 (템플릿 리터럴 → 컴포넌트 구조화)
- 모듈화된 SPA 구조 설계 (pages, router, store)
- history fallback 처리 및 배포 시 주의사항
등을 이어서 다루겠습니다.
📌 이전 글 다시보기
👉 JavaScript 모듈 시스템 완전 이해하기 – CommonJS vs ESModules
📌 다음 글 미리보기
📚 JavaStript 시리즈 전체 보기
👉 https://jobreview.tistory.com/category/language/javascript
'architecture_spa' 카테고리의 다른 글
ESModules 심화1: 동적 import(), 번들러 처리 방식, tsconfig 설정 가이드 (0) | 2025.04.26 |
---|---|
Web Vitals(LCP, CLS, FID)과 Lighthouse 성능 측정 실전 (1) | 2025.04.26 |
SPA 구조 설계(모듈화): 라우터/스토어 모듈 분리와 파일 구조 구성법 (1) | 2025.04.26 |
브라우저 렌더링 구조와 성능 최적화 – 웹페이지가 그려지는 과정을 이해하고 빠르게 만들기 (0) | 2025.04.20 |
JavaScript 모듈 시스템 완전 이해하기 – CommonJS vs ESModules (0) | 2025.04.20 |
댓글