테마
Ajax를 이용한 템플릿 통합
Ajax(fetch API)로 다른 팀 서버의 HTML 프래그먼트를 비동기 요청하여 현재 페이지 DOM에 삽입하는 마이크로 프론트엔드 통합 방식의 원리, 구현 패턴, 장단점을 학습한다.
학습 목표
- Ajax 기반 템플릿 통합의 동작 원리를 도식으로 설명할 수 있다
- 비동기 프래그먼트 로딩의 구현 패턴(fetch + innerHTML)을 이해한다
- 이 방식의 장점(비동기 로딩, 구현 단순성)과 단점(URL 문제, 격리, SEO)을 명확히 구분한다
- 실제 서비스에서 이 방식이 적합한 상황과 부적합한 상황을 판단할 수 있다
1. Ajax 프래그먼트 통합이란
Ajax(Asynchronous JavaScript and XML)는 자바스크립트를 이용해 비동기적으로 서버 데이터를 요청하는 기법이다. 현재는 XML보다 JSON이나 HTML을 주로 사용하며, XMLHttpRequest 대신 fetch API가 표준이다.
마이크로 프론트엔드에서 Ajax 통합이란, 한 팀의 페이지에서 다른 팀 서버의 HTML 프래그먼트를 fetch로 가져와 DOM에 삽입하는 것이다. 각 프래그먼트는 독립된 서버에서 제공되므로, 팀별로 독립적인 개발과 배포가 가능해진다.
2. 동작 원리
2.1 전체 아키텍처
동작 순서:
- 사용자가 팀 홈 서버(
:3001)에 페이지를 요청한다 - 서버가 메인 HTML과 JavaScript를 응답한다
- JavaScript가 실행되면서
fetch()로 팀 잡스 서버(:3002)에 프래그먼트를 요청한다 - 팀 잡스 서버가 HTML 프래그먼트를 응답한다
- 동시에 팀 네트워크 서버(
:3003)에도 다른 프래그먼트를 요청한다 - 응답받은 HTML을
innerHTML로 페이지의 지정된 슬롯에 삽입한다
2.2 구현 패턴
기본적인 구현은 다음과 같은 패턴을 따른다.
html
<!-- 팀 홈의 index.html -->
<div id="main">
<h1>메인 페이지</h1>
<div id="recommendation-slot">로딩 중...</div>
<div id="status-slot">로딩 중...</div>
</div>
<script>
// 선언적으로 데이터 속성에 프래그먼트 URL 지정
async function loadFragment(slotId, url) {
const slot = document.getElementById(slotId);
try {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
slot.innerHTML = await res.text();
} catch (err) {
slot.innerHTML = '<p>콘텐츠를 불러올 수 없습니다.</p>';
}
}
loadFragment('recommendation-slot', 'http://localhost:3002/fragments/recommendation/');
loadFragment('status-slot', 'http://localhost:3003/fragments/status/');
</script>핵심은 fetch()로 다른 서버의 HTML을 받아 innerHTML로 삽입하는 것이다. try-catch를 통해 에러 처리와 폴백 UI를 쉽게 구현할 수 있다.
3. 프래그먼트 URL 네이밍 규칙
프래그먼트를 서빙하는 URL은 팀 간 규약이 필요하다. 일반적으로 다음과 같은 계층 구조를 사용한다.
/{team-name}/fragments/{fragment-name}/index.html| 세그먼트 | 예시 | 설명 |
|---|---|---|
| team-name | jobs, network | 프래그먼트를 소유한 팀 |
| fragments | 고정 | 프래그먼트임을 명시하는 네임스페이스 |
| fragment-name | recommendation | 프래그먼트의 기능적 이름 |
이 규칙을 따르면 어떤 팀의 어떤 프래그먼트인지 URL만으로 파악할 수 있고, 프록시 서버에서 라우팅 규칙을 설정할 때도 편리하다.
4. 스타일과 스크립트 처리
4.1 스타일 포함 방식
프래그먼트에 스타일을 포함하는 방법은 크게 세 가지이다.
권장 사항:
- 클래스명에 팀별 접두사를 붙인다 (예:
.jobs-recommendation__title) - BEM이나 CSS Modules 같은 네이밍 규칙을 도입한다
- 가능하면 인라인 스타일이나
style태그 방식을 사용하여 기존 문서 스타일과의 충돌을 줄인다
4.2 스크립트 격리
프래그먼트에 포함된 JavaScript는 메인 페이지와 같은 전역 스코프에서 실행된다. 따라서:
- 전역 변수 사용 금지: 반드시 IIFE나 모듈 패턴으로 스코프를 격리한다
- 이벤트 리스너 관리: 프래그먼트가 제거될 때 등록한 이벤트 리스너도 함께 정리해야 한다
- 페이지 스크립트와 연동: 프래그먼트에서 메인 페이지의 함수를 호출해야 한다면, CustomEvent를 사용한다
javascript
// 프래그먼트 측: 이벤트 발행
document.dispatchEvent(new CustomEvent('jobs:recommendation:select', {
detail: { jobId: 123 }
}));
// 페이지 측: 이벤트 구독
document.addEventListener('jobs:recommendation:select', (e) => {
console.log('선택된 채용공고:', e.detail.jobId);
});5. 장점
5.1 비동기 로딩과 점진적 렌더링
메인 페이지가 먼저 렌더링되고, 프래그먼트는 비동기로 채워진다. 사용자는 페이지의 주요 콘텐츠를 즉시 볼 수 있으며, 부가 정보는 순차적으로 나타난다.
5.2 구현의 단순함
fetch + innerHTML이라는 웹 표준 API만 사용하므로 별도의 프레임워크나 빌드 도구가 필요 없다. 기존 프로젝트에 가장 적은 비용으로 도입할 수 있다.
5.3 동일 문서 내 실행
iframe과 달리 별도의 document를 생성하지 않으므로 성능 오버헤드가 적고, 프래그먼트의 높이가 자동으로 문서 흐름에 맞춰진다.
5.4 에러 처리 용이
try-catch-finally 패턴으로 로딩 상태, 에러 상태, 폴백 UI를 간단하게 관리할 수 있다.
6. 단점
6.1 URL 라우팅 문제
프래그먼트를 가져오는 URL이 절대 경로여야 한다. 개발 환경에서는 localhost:3002이지만 프로덕션에서는 다른 도메인이나 프록시 경로를 사용해야 하므로, 환경별 URL 관리가 필요하다.
6.2 스타일과 스크립트 격리 부재
동일한 document에 삽입되므로 CSS 클래스명 충돌, 전역 변수 오염 등이 발생할 수 있다. 팀 간 네이밍 규칙 합의와 스코프 격리 패턴 적용이 필수적이다.
6.3 네트워크 의존성
UI가 네트워크 상태에 직접적으로 의존한다. 프래그먼트를 제공하는 서버가 느리거나 장애가 발생하면 해당 영역이 비어 보이거나 깜빡이는 현상이 나타난다.
6.4 SEO 불리
검색 엔진 크롤러가 JavaScript를 실행하지 않으면 프래그먼트 영역이 비어 있는 것으로 인식된다. 핵심 콘텐츠가 프래그먼트에 있다면 SEO에 치명적이다.
6.5 중복 로딩 위험
같은 프래그먼트를 한 페이지의 여러 곳에서 사용하면, 동일한 HTML/CSS/JS를 중복으로 로드하게 된다. 스타일 충돌이나 데이터 오염의 원인이 될 수 있다.
6.6 크로스 프래그먼트 통신의 복잡성
프래그먼트 간에 데이터를 주고받으려면 CustomEvent나 전역 이벤트 버스 같은 추가적인 구현이 필요하다. 프래그먼트 수가 많아지면 이벤트 관리가 복잡해진다.
7. 적합한 사용 시나리오
핵심 정리
- Ajax 템플릿 통합은
fetch()로 HTML 프래그먼트를 비동기 요청하여innerHTML로 DOM에 삽입하는 방식이다. - 장점: 구현이 단순하고, 비동기 로딩으로 점진적 렌더링이 가능하며, iframe 대비 성능 오버헤드가 적다.
- 단점: 스타일/스크립트 격리가 안 되고, URL이 절대 경로여야 하며, SEO에 불리하고, 네트워크 상태에 UI가 의존적이다.
- 서버에서 완성된 HTML을 생성하여 내려주는 경우에 가장 적합하며, 복잡한 인터랙션이나 SEO가 중요한 경우에는 부적합하다.
- 프로덕션에서 사용한다면 네임스페이스 규칙, IIFE 패턴, CustomEvent 기반 통신 등 격리와 통신을 위한 추가 작업이 반드시 필요하다.
다음 단계
- Nginx 프록시 기반 페이지 분리 및 통합: 리버스 프록시를 이용해 URL 경로별로 서로 다른 팀 서버를 연결하는 Linked SPA 패턴을 학습한다.