Skip to content

iframe을 이용한 클라이언트 통합

iframe은 가장 오래되고 가장 단순한 클라이언트 통합 방식으로, 별도의 브라우저 컨텍스트를 생성하여 CSS/JS/DOM을 완벽하게 격리하지만, 성능 오버헤드와 반응형 처리, 접근성, SEO 문제로 인해 고객 대면 서비스에는 권장되지 않는다.

학습 목표

  • iframe의 동작 원리(중첩 브라우저 컨텍스트)를 이해한다
  • iframe이 제공하는 완전한 격리의 범위와 그로 인한 트레이드오프를 설명할 수 있다
  • iframe 기반 마이크로프론트엔드의 통합 구조와 통신 방식(postMessage)을 구현할 수 있다
  • iframe 통합의 장단점을 비교하여 적절한 적용 시나리오를 판별할 수 있다
  • iframe과 Web Components 격리 방식의 차이를 명확히 구분할 수 있다

1. iframe 기본 개념

iframe(Inline Frame Element)은 현재 HTML 문서 안에 다른 HTML 문서를 삽입하는 HTML 요소이다. <div>, <p>처럼 하나의 HTML 태그이지만, 태그 안에 완전히 별도의 브라우저 컨텍스트(browsing context)가 생성된다는 점이 근본적으로 다르다.

html
<!-- 가장 기본적인 iframe 사용 -->
<iframe src="http://localhost:3002/fragments/recommendation"
        width="100%"
        height="220"
        frameborder="0">
</iframe>

iframe의 핵심 특성:

특성설명
별도 documentiframe 내부는 독립된 document 객체를 가진다
별도 windowiframe 내부는 자체 window 객체를 가진다
별도 브라우저 컨텍스트CSS, JS, DOM이 완전히 분리된 환경에서 실행된다
독립 히스토리iframe 내부 네비게이션은 자체 히스토리 스택을 가진다

2. iframe 기반 마이크로프론트엔드 구조

iframe을 마이크로프론트엔드에 적용하는 구조는 매우 직관적이다. Shell 앱의 특정 영역에 <iframe> 태그를 배치하고, src 속성으로 각 팀의 마이크로앱 URL을 지정하면 된다.

2.1 기본 통합 예제

html
<!-- Shell 앱: index.html -->
<div id="main">
  <h1>메인 콘텐츠</h1>
  <p>Shell 앱에서 직접 관리하는 영역</p>
</div>

<div id="team-jobs-recommendation">
  <!-- 팀 Jobs의 마이크로앱을 iframe으로 삽입 -->
  <iframe src="http://localhost:3002/jobs/fragments/recommendation"
          width="100%"
          height="220"
          frameborder="0"
          title="추천 채용 공고">
  </iframe>
</div>

iframe 내부의 마이크로앱은 자체적으로 완결된 HTML 문서이다. API 호출, 스타일 적용, 이벤트 처리 모두 iframe 내부에서 독립적으로 수행한다.

javascript
// iframe 내부 마이크로앱: main.ts
fetch('/jobs/api/recommendations.json')
  .then(response => response.json())
  .then(({ recommendations }) => {
    const container = document.querySelector('.recommendations');
    container.innerHTML = recommendations
      .map(rec => `<div><a href="${rec.url}">${rec.name}</a></div>`)
      .join('');
  });

2.2 iframe sandbox 속성

sandbox 속성으로 iframe 내부의 권한을 세밀하게 제어할 수 있다. 마이크로프론트엔드에서는 보안 강화를 위해 적극 활용한다.

html
<iframe src="http://micro-app.example.com"
        sandbox="allow-scripts allow-same-origin allow-forms"
        title="팀 A 마이크로앱">
</iframe>
sandbox 값허용하는 동작
(빈 값)모든 기능 차단 (JS 실행 불가, 폼 제출 불가)
allow-scriptsJavaScript 실행 허용
allow-same-originSame-origin 정책 적용 (쿠키, 로컬스토리지 접근)
allow-forms폼 제출 허용
allow-popups새 창/탭 열기 허용
allow-top-navigation부모 프레임의 URL 변경 허용

3. iframe 간 통신: postMessage

iframe의 완전한 격리는 장점이지만, 마이크로앱 간 또는 마이크로앱과 Shell 간에 데이터를 주고받아야 할 때는 window.postMessage() API를 사용해야 한다.

3.1 postMessage 통신 구현

javascript
// Shell 앱: iframe으로 메시지 전송
const iframe = document.getElementById('micro-app-frame');
iframe.contentWindow.postMessage(
  { type: 'USER_CHANGED', payload: { userId: 42, name: '김개발' } },
  'http://localhost:3002'  // 수신 대상의 origin (보안을 위해 명시)
);

// Shell 앱: iframe으로부터 메시지 수신
window.addEventListener('message', (event) => {
  // origin 검증 (보안 필수)
  if (event.origin !== 'http://localhost:3002') return;

  const { type, payload } = event.data;
  switch (type) {
    case 'NAVIGATE':
      window.location.href = payload.path;
      break;
    case 'RESIZE':
      iframe.style.height = payload.height + 'px';
      break;
  }
});
javascript
// iframe 내부 마이크로앱: 부모 창으로 메시지 전송
// 링크 클릭 시 부모 창의 URL을 변경하는 예
document.querySelectorAll('.recommendations a').forEach(a => {
  a.addEventListener('click', (event) => {
    event.preventDefault();
    window.parent.postMessage(
      { type: 'NAVIGATE', payload: { path: a.href } },
      'http://localhost:3000'  // Shell 앱의 origin
    );
  });
});

3.2 postMessage 보안 주의사항

주의사항설명
origin 검증 필수event.origin을 반드시 확인하여 신뢰할 수 있는 출처만 허용
targetOrigin 명시postMessage()의 두 번째 인자로 수신 대상 origin을 명시. '*'는 개발 환경에서만 사용
데이터 검증수신된 메시지의 typepayload 형식을 검증 후 처리
구조화된 메시지 규약{ type, payload } 형태의 일관된 메시지 규약을 팀 간에 합의

4. iframe의 근본적 문제

4.1 성능 오버헤드

iframe은 완전히 새로운 브라우저 컨텍스트를 생성한다. 이는 곧 별도의 메모리 할당, DOM 트리 구축, CSS 파싱, JavaScript 엔진 초기화를 의미한다.

항목일반 DOM 요소iframe
문서 파싱부모 문서에 포함별도 문서 전체 파싱
CSS 파싱부모 스타일시트 공유별도 스타일시트 로드/파싱
JS 컨텍스트부모 window 공유별도 window 객체 생성
메모리부모 문서 메모리 내추가 메모리 할당
네트워크 요청추가 없음HTML, CSS, JS 별도 로드

페이지에 iframe이 3~4개만 있어도 초기 로딩 시간과 메모리 사용량이 눈에 띄게 증가한다.

4.2 반응형 디자인 어려움

iframe의 높이는 내부 콘텐츠에 자동으로 맞춰지지 않는다. 외부에서 고정 높이를 지정하거나, 내부에서 postMessage로 콘텐츠 높이를 알려주고 외부에서 조정하는 추가 작업이 필요하다.

javascript
// iframe 내부: 콘텐츠 높이 변경 시 부모에게 알림
const resizeObserver = new ResizeObserver(() => {
  window.parent.postMessage({
    type: 'RESIZE',
    payload: { height: document.body.scrollHeight }
  }, '*');
});
resizeObserver.observe(document.body);

// Shell 앱: iframe 높이 동적 조정
window.addEventListener('message', (event) => {
  if (event.data.type === 'RESIZE') {
    document.getElementById('micro-app-frame').style.height =
      event.data.payload.height + 'px';
  }
});

이러한 높이 동기화 로직은 팀 간 결합을 만들어내고, 동적 콘텐츠(로딩 상태, 에러 상태, 접기/펼치기 등)에서 버그의 원인이 된다.

4.3 기타 문제

문제설명
SEO검색엔진은 iframe 내용을 부모 페이지의 콘텐츠로 색인하지 않는다. iframe은 별개 페이지로 취급된다
접근성(a11y)스크린 리더가 iframe 경계를 넘나드는 것이 어렵다. 키보드 탭 순서가 복잡해진다
딥링크iframe 내부의 상태/경로가 브라우저 주소창에 반영되지 않는다
브라우저 히스토리iframe 내부 네비게이션이 부모 브라우저의 뒤로가기 버튼에 예상치 못한 영향을 줄 수 있다
모바일모바일 브라우저에서 iframe 내부의 스크롤, 확대/축소가 자연스럽지 않다

5. iframe 통합을 사용할 수 있는 경우

iframe의 단점이 많지만, 특정 시나리오에서는 여전히 합리적인 선택이 될 수 있다.

iframe이 적합한 경우:

  • 내부 관리자 도구(Admin Panel) 통합
  • 고도의 격리가 필수인 서드파티 위젯 삽입 (결제 모듈, 채팅 위젯 등)
  • 레거시 애플리케이션을 빠르게 통합해야 하는 과도기
  • SEO, 접근성, 성능이 크게 중요하지 않은 데스크탑 전용 내부 시스템

iframe이 부적합한 경우:

  • 고객 대면 웹 서비스 (SEO, 성능, 접근성 중요)
  • 모바일 최적화가 필요한 서비스
  • 마이크로앱 간 빈번한 데이터 교환이 필요한 경우
  • 일관된 사용자 경험(UX)이 요구되는 경우

핵심 정리

핵심 개념요약
iframe이란현재 페이지에 별도 브라우저 컨텍스트를 생성하여 다른 HTML 문서를 삽입하는 HTML 요소
격리 수준CSS, JS, DOM이 완전히 분리되는 가장 강력한 격리. 별도 document, 별도 window
통신 방식window.postMessage() API를 통해 메시지를 주고받음. origin 검증이 보안상 필수
성능별도 브라우저 컨텍스트 생성으로 추가 메모리, CPU 비용 발생. iframe이 늘어날수록 비용 증가
반응형내부 콘텐츠에 자동 맞춤 불가. postMessage 기반 높이 동기화 필요
SEO검색엔진이 iframe 내용을 부모 페이지 콘텐츠로 인식하지 않음
적합한 용도관리자 도구, 서드파티 위젯, 레거시 과도기 통합 등 제한적 시나리오
부적합한 용도고객 대면 서비스, 모바일 최적화 필요 서비스

다음 단계

지금까지 클라이언트 측 통합 방식 중 Web Components와 iframe을 상세히 살펴보았다. 다음 장에서는 SSI, 빌드타임, iframe, Web Components, JS 통합, Module Federation 등 모든 통합 방식을 종합적으로 비교하고, 상황별 추천 방식을 정리한다.

다음: 클라이언트 통합 비교 정리 ->