본문 바로가기
architecture_spa

프레임워크 없이 바닐라 JS로 SPA 만들기 – 라우팅, 렌더링, 상태관리 직접 구현해보기

by 죄니안죄니 2025. 4. 20.

들어가며

 

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

댓글