iframe 기반 레거시 SPA 구조에서 JavaScript 라이브러리 중복 로딩 개선하기
iframe 기반 레거시 SPA 구조는 여러 페이지를 iframe으로 불러오고 슬라이더 방식으로 화면을 전환해 하나의 앱처럼 보이게 만드는 구조다. 당시에는 WebView 또는 데스크톱 앱 환경에서 화면 전환을 구현하기 위한 현실적인 선택이었을 수 있다. 하지만 시간이 지나며 공통 파일에 무거운 JavaScript 라이브러리가 추가되면서 iframe마다 같은 리소스가 중복 로드되는 문제가 생길 수 있다. 이를 줄이기 위해 부모 창에서 라이브러리를 한 번만 로드하고 자식 iframe은 부모 창의 객체를 참조하는 방식으로 개선할 수 있다.
iframe 기반 레거시 SPA 구조에서 JavaScript 라이브러리 중복 로딩 개선하기
정의
iframe 기반 레거시 SPA 구조는 여러 개의 화면을 iframe으로 불러오고, 사용자에게는 하나의 앱 안에서 화면이 전환되는 것처럼 보여주는 구조다.
SPA는 Single Page Application의 줄임말이다. 하나의 페이지 안에서 화면만 바뀌며 앱처럼 동작하는 웹 애플리케이션 방식을 말한다.
다만 여기서 말하는 구조는 React나 Vue로 만든 정식 SPA는 아니다. 여러 개의 개별 페이지를 iframe으로 불러오고, 슬라이더 방식으로 화면을 전환하는 구조다. 그래서 “iframe 기반 레거시 SPA형 구조”라고 볼 수 있다.
메인 화면
└── 화면 전환 영역
├── iframe - 첫 번째 화면
├── iframe - 두 번째 화면
├── iframe - 세 번째 화면
└── iframe - 여러 개의 화면
iframe은 현재 페이지 안에 다른 HTML 문서를 넣는 태그다. 쉽게 말하면 하나의 화면 안에 작은 브라우저 창을 하나 더 넣는 방식이다.
이 구조에서는 각 iframe이 하나의 독립된 화면처럼 동작한다. 사용자는 화면이 전환되는 것처럼 보지만, 내부적으로는 여러 개의 페이지가 iframe으로 각각 실행되고 있다.
필요한 이유
AD
제휴 광고 · 일부 링크는 수수료를 받을 수 있습니다
iframe 기반 레거시 SPA 구조는 현재 기준으로 보면 복잡해 보일 수 있다. 하지만 당시 개발 환경에서는 충분히 선택할 수 있는 방식이었을 수 있다.
첫째, WebView 또는 데스크톱 앱 환경에서는 일반 웹사이트와 기준이 다르다. WebView는 앱 안에서 웹 화면을 보여주는 브라우저 영역이다. HTML, CSS, JavaScript로 만든 화면을 앱이나 실행 프로그램 안에서 보여줄 수 있다.
일반 웹사이트에서는 URL, 뒤로 가기, 검색엔진 노출이 중요하다. URL은 웹페이지 주소다. 라우팅은 URL이나 상태에 따라 어떤 화면을 보여줄지 정하는 방식이다. 검색엔진 노출은 구글 같은 검색엔진이 페이지를 찾고 보여주는 것을 말한다.
하지만 WebView나 데스크톱 앱 환경에서는 사용자가 주소창을 직접 보지 않을 수 있다. 검색엔진 노출이 필요하지 않을 수도 있다. 이 경우에는 URL 구조보다 화면 전환 경험이 더 중요했을 수 있다.
둘째, React나 Vue 같은 SPA 프레임워크를 도입하기 어려운 상황이었을 수 있다. 프레임워크는 개발에 필요한 구조와 기능을 미리 제공하는 도구다. React와 Vue는 화면을 컴포넌트 단위로 만들고, 상태에 따라 화면을 바꾸는 데 많이 사용된다.
기존 시스템이 PHP 중심으로 만들어져 있었다면, 전체 구조를 React나 Vue로 바꾸는 일은 쉽지 않다. 기존 페이지, 공통 파일, 서버 렌더링 방식, 배포 방식까지 함께 바뀔 수 있기 때문이다.
셋째, iframe은 기존 페이지를 분리해서 재사용하기 쉽다. 각 화면을 독립된 파일로 만들고, 메인 화면에서는 iframe으로 불러오면 된다. 기존 페이지를 크게 수정하지 않고도 화면 전환 구조에 넣을 수 있다.
즉, iframe 기반 레거시 SPA 구조는 무조건 잘못된 구조라고 보기 어렵다. 당시의 실행 환경, 일정, 기술 스택, 유지보수 방식 안에서 나온 현실적인 선택이었을 수 있다.
문제는 시간이 지나면서 기능이 커졌다는 점이다. 처음에는 가벼운 화면만 iframe으로 불러왔을 수 있다. 하지만 이후 공통 파일에 무거운 JavaScript 라이브러리가 추가되면, iframe 구조와 결합되면서 성능 문제가 생길 수 있다.
핵심 개념
핵심 문제는 공통 파일에 포함된 JavaScript 라이브러리가 iframe 개수만큼 중복 로드될 수 있다는 점이다.
JavaScript 라이브러리는 자주 쓰는 기능을 미리 만들어 둔 코드 묶음이다. 직접 모든 기능을 만들지 않고, 이미 만들어진 기능을 가져와 사용할 수 있게 해준다.
예를 들어 이미지 처리, 그래픽 편집, 차트 표시 같은 기능은 직접 만들기 어렵고 양도 많다. 이럴 때 OpenCV, Konva.js, ECharts 같은 라이브러리를 사용할 수 있다.
- OpenCV: 이미지 처리와 컴퓨터 비전 기능을 제공하는 라이브러리다. 컴퓨터 비전은 이미지나 영상에서 정보를 분석하는 기술이다.
- Konva.js: Canvas 위에 도형, 이미지, 텍스트 등을 쉽게 그리게 해주는 JavaScript 라이브러리다. Canvas는 웹에서 그래픽을 그릴 수 있는 HTML 요소다.
- ECharts: 차트와 그래프를 그리는 JavaScript 라이브러리다. 막대그래프, 선그래프, 원형차트 등을 만들 수 있다.
이런 라이브러리들은 기능이 많은 만큼 파일 크기와 초기화 비용이 클 수 있다. 초기화 비용은 라이브러리를 사용할 준비를 하기 위해 브라우저가 처리해야 하는 작업량을 뜻한다.
기존 구조에서는 여러 iframe 페이지가 공통 헤더 파일을 불러올 수 있다. 공통 헤더 파일은 여러 화면에서 같이 사용하는 CSS, JavaScript, 설정 등을 모아 둔 파일이다.
각 화면
→ 공통 헤더 파일 불러오기
→ 공통 CSS와 JavaScript 로드
이 방식 자체는 일반적이다. 공통 코드를 한 곳에서 관리할 수 있기 때문이다.
문제는 이 방식이 iframe 구조와 결합될 때 생긴다. iframe은 각각 독립된 문서처럼 동작한다. 따라서 iframe 안의 여러 화면이 모두 같은 공통 헤더 파일을 불러오면, 각 iframe마다 같은 JavaScript 파일을 다시 불러올 수 있다.
첫 번째 iframe → 공통 헤더 → 무거운 라이브러리 로드
두 번째 iframe → 공통 헤더 → 무거운 라이브러리 로드
세 번째 iframe → 공통 헤더 → 무거운 라이브러리 로드
...
여러 번째 iframe → 공통 헤더 → 무거운 라이브러리 로드
iframe이 많아질수록 같은 라이브러리가 반복해서 로드될 수 있다. 사용자가 실제로 보고 있는 화면은 하나여도, 보이지 않는 iframe들이 각자 리소스를 들고 있을 수 있다.
주변 기초 개념
1. 레거시 시스템
레거시 시스템은 오래전부터 운영되어 온 기존 시스템을 말한다. 오래되었다는 뜻이지, 무조건 나쁘다는 뜻은 아니다.
레거시 시스템은 실제 업무 흐름과 많은 기능을 이미 담고 있다. 그래서 전체 구조를 한 번에 바꾸기 어렵다. 작은 수정도 다른 화면이나 기능에 영향을 줄 수 있다.
레거시 시스템을 다룰 때는 기존 구조를 먼저 이해해야 한다. 그다음 현재 문제가 되는 부분을 좁혀서 안전하게 개선해야 한다.
2. iframe 기반 SPA형 구조
iframe 기반 SPA형 구조는 여러 페이지를 iframe으로 나누어 불러오면서, 겉으로는 하나의 앱처럼 보이게 만드는 방식이다.
정식 SPA는 보통 하나의 HTML 안에서 JavaScript 라우터가 화면을 바꾼다. 라우터는 현재 주소나 상태에 따라 어떤 화면을 보여줄지 결정하는 기능이다.
반면 iframe 기반 SPA형 구조는 화면마다 별도 페이지가 존재한다. 그리고 메인 화면이 그 페이지들을 iframe으로 감싸서 보여준다.
정식 SPA:
하나의 메인 페이지
→ JavaScript가 화면을 바꿈
iframe 기반 SPA형 구조:
메인 화면
→ 여러 iframe 페이지를 불러와 전환함
사용자 입장에서는 둘 다 앱처럼 보일 수 있다. 하지만 내부 구조는 다르다.
3. WebView
WebView는 앱 안에서 웹 페이지를 보여주는 브라우저 영역이다. HTML, CSS, JavaScript로 만든 화면을 앱 안에서 실행할 수 있게 해준다.
WebView 환경에서는 웹 기술로 화면을 만들면서도, 사용자는 일반 브라우저가 아니라 앱 화면으로 사용한다. 그래서 일반 웹사이트와 설계 기준이 다를 수 있다.
4. 부모 창과 자식 iframe
iframe을 포함하고 있는 바깥 페이지를 부모 창이라고 한다. iframe 안에서 실행되는 페이지를 자식 iframe이라고 한다.
부모 창
└── 자식 iframe
부모 창은 전체 화면의 기준이 되는 바깥 문서다. 자식 iframe은 부모 창 안에 들어온 개별 화면이다.
5. window.self, window.top, window.parent
JavaScript에서는 현재 코드가 부모 창에서 실행 중인지, iframe 내부에서 실행 중인지 확인할 수 있다.
window.self !== window.top
window.self: 현재 코드가 실행 중인 창이다.window.top: 가장 바깥에 있는 최상위 창이다.window.self !== window.top: 현재 창이 최상위 창이 아니면 iframe 안에 있다는 뜻이다.
window.parent는 현재 iframe을 감싸고 있는 부모 창을 의미한다.
자식 iframe에서 부모 창에 있는 값을 가져오고 싶을 때 사용할 수 있다.
단, 부모 창과 iframe이 서로 접근 가능한 환경이어야 한다. 보통 같은 도메인일 때 가능하다. 도메인은 웹사이트 주소의 기준이 되는 이름이다.
6. 메모리
메모리는 프로그램이 실행 중인 데이터를 임시로 저장하는 공간이다. JavaScript 라이브러리를 불러오면 브라우저는 해당 코드를 메모리에 올린다.
같은 라이브러리를 여러 iframe에서 반복해서 불러오면, 비슷한 데이터가 여러 번 메모리에 올라갈 수 있다. 이것이 많아지면 프로그램이 느려질 수 있다.
실제 흐름
기존 흐름
기존 구조에서는 각 iframe 페이지가 독립적으로 실행된다. 그리고 각 페이지가 공통 헤더 파일을 불러온다.
1. 메인 화면이 열린다.
2. 화면 전환 영역이 생성된다.
3. 여러 화면이 iframe으로 로드된다.
4. 각 iframe 화면이 공통 헤더 파일을 불러온다.
5. 공통 헤더 안의 JavaScript 라이브러리가 각 iframe에서 로드된다.
6. iframe 개수만큼 같은 라이브러리가 반복 로드될 수 있다.
이 흐름에서는 iframe 개수가 많아질수록 중복 로딩 가능성도 커진다.
문제가 되는 이유
iframe은 각각 독립된 문서다. 그래서 같은 공통 헤더 파일을 사용해도, 브라우저는 각 iframe 안에서 별도의 문서로 처리한다.
결과적으로 무거운 JavaScript 라이브러리가 iframe마다 다시 준비될 수 있다. 이때 다음 문제가 발생할 수 있다.
- 초기 화면 로딩이 느려진다.
- 메모리 사용량이 증가한다.
- 화면 전환이 버벅일 수 있다.
- 앱 응답 속도가 떨어질 수 있다.
- 장시간 사용 시 프로그램이 불안정해질 수 있다.
개선 흐름
AD
제휴 광고 · 일부 링크는 수수료를 받을 수 있습니다
옆커폰
개선 방향은 부모 창을 공통 자원 저장소처럼 사용하는 것이다. 부모 창에서 무거운 라이브러리를 한 번만 로드한다. 그리고 자식 iframe은 부모 창에 올라간 객체를 참조한다.
1. 현재 창이 부모 창인지 iframe인지 확인한다.
2. 부모 창이면 공통 라이브러리를 한 번만 로드한다.
3. iframe이면 라이브러리를 새로 로드하지 않는다.
4. iframe은 부모 창에 이미 올라간 라이브러리 객체를 참조한다.
이렇게 하면 기존 iframe 구조는 유지할 수 있다. 동시에 무거운 JavaScript 라이브러리의 중복 로딩을 줄일 수 있다.
예시
보안상 실제 프로젝트의 파일 경로, 변수명, 디렉터리명은 제외하고 원리만 단순화해서 설명한다.
기존 방식
각 iframe 화면
→ 공통 헤더 파일 로드
→ 공통 라이브러리 로드
이 방식은 관리하기 쉽다. 공통 파일에 필요한 CSS와 JavaScript를 모아둘 수 있기 때문이다.
하지만 iframe이 여러 개라면 같은 공통 라이브러리가 반복해서 로드될 수 있다.
iframe 1 → 라이브러리 로드
iframe 2 → 라이브러리 로드
iframe 3 → 라이브러리 로드
iframe 4 → 라이브러리 로드
이 구조에서는 화면 수가 늘어날수록 메모리 사용량도 함께 늘어날 수 있다.
개선 방식
부모 창
→ 공통 라이브러리 1회 로드
자식 iframe
→ 라이브러리 재로드 안 함
→ 부모 창의 라이브러리 객체 참조
핵심은 “로드는 부모 창에서 한 번만 하고, 사용은 각 iframe에서 공유한다”는 것이다.
이를 위해 현재 창이 iframe인지 확인한다.
현재 창이 최상위 창이면 → 부모 창
현재 창이 최상위 창이 아니면 → iframe 내부
JavaScript에서는 다음 조건으로 구분할 수 있다.
window.self !== window.top
window.self: 현재 코드가 실행 중인 창이다.window.top: 가장 바깥에 있는 최상위 창이다.- 두 값이 다르면 현재 코드는 iframe 안에서 실행 중이라는 뜻이다.
전체 원리는 다음과 같이 정리할 수 있다.
if 부모 창이라면:
공통 라이브러리를 한 번만 로드한다.
else iframe 내부라면:
공통 라이브러리를 다시 로드하지 않는다.
부모 창의 라이브러리 객체를 참조한다.
실제 적용 시에는 각 프로젝트에서 사용하는 라이브러리 경로와 객체 이름에 맞게 처리하면 된다. 블로그 글에서는 실제 경로나 변수명을 공개하지 않고, 이처럼 동작 원리만 설명하는 것이 안전하다.
주의점
1. 같은 도메인인지 확인해야 한다
iframe에서 부모 창의 객체를 참조하려면 보안 정책상 접근이 허용되어야 한다. 보통 부모 창과 iframe이 같은 도메인일 때 가능하다.
서로 다른 도메인이라면 브라우저가 접근을 막을 수 있다. 이 경우에는 postMessage 같은 별도 통신 방식을 사용해야 한다. postMessage는 부모 창과 iframe이 메시지를 주고받게 해주는 JavaScript 기능이다.
2. 부모 라이브러리 로드 완료 시점을 확인해야 한다
자식 iframe이 너무 빨리 실행되면 부모 창의 라이브러리가 아직 로드되지 않았을 수 있다. 이 경우 iframe에서 부모 창의 객체를 참조하려고 해도 값이 없을 수 있다.
실제 적용 시에는 부모 창에서 라이브러리 로드가 끝난 뒤 iframe을 초기화하는 방식이 더 안전하다.
3. 모든 라이브러리가 공유에 적합한 것은 아니다
일부 라이브러리는 각 문서마다 따로 초기화되어야 할 수 있다. 문서 컨텍스트는 HTML 문서가 실행되는 독립된 환경을 뜻한다.
따라서 부모 객체를 참조하는 방식이 해당 라이브러리에서 문제없이 동작하는지 확인해야 한다.
4. CSS 중복도 비용이 있지만 우선순위는 다를 수 있다
CSS는 화면 스타일을 정하는 코드다. iframe이 여러 개면 CSS도 각 iframe 안에서 다시 해석될 수 있다.
하지만 무거운 JavaScript 라이브러리 중복 로딩이 더 큰 병목일 가능성이 높다. 따라서 먼저 JavaScript 중복 로딩을 줄이고, 이후 필요하면 CSS 최적화를 검토하는 것이 현실적이다.
5. 전체 재작성보다 영향 범위를 줄이는 것이 중요할 수 있다
성능 문제가 있다고 해서 항상 전체 구조를 바로 바꿀 수 있는 것은 아니다. 기존 구조를 바꾸면 다른 화면, 공통 파일, 배포 방식까지 영향을 줄 수 있다.
이 개선 방식은 전체 구조를 즉시 재작성하는 방법이 아니다. 기존 iframe 기반 레거시 SPA 구조를 유지하면서, 가장 큰 병목인 JavaScript 라이브러리 중복 로딩을 먼저 줄이는 방법이다.
요약
iframe 기반 레거시 SPA 구조는 여러 페이지를 iframe으로 불러오고, 화면 전환 영역에서 하나의 앱처럼 보여주는 방식이다.
이 구조는 WebView나 데스크톱 앱 환경에서 화면 전환을 구현하기 위한 현실적인 선택이었을 수 있다. 일반 웹사이트와 달리 주소창, 검색엔진 노출, URL 라우팅이 중요하지 않은 환경에서는 이런 방식이 사용될 수 있다.
하지만 iframe은 각각 독립된 문서처럼 동작한다. 그래서 각 iframe 페이지가 공통 헤더 파일을 불러오면, 그 안에 있는 JavaScript 라이브러리도 iframe 개수만큼 중복 로드될 수 있다.
OpenCV, Konva.js, ECharts처럼 무거운 라이브러리가 여러 번 로드되면 초기 로딩 속도, 메모리 사용량, 앱 응답성에 영향을 줄 수 있다.
이를 줄이기 위해 부모 창에서 라이브러리를 한 번만 로드하고, 자식 iframe에서는 부모 창의 객체를 참조하는 방식을 사용할 수 있다.
이 방법은 전체 구조를 바로 바꾸기 어려운 상황에서 적용할 수 있는 현실적인 개선 방법이다. 단, 같은 도메인 여부, 로드 완료 시점, 라이브러리 공유 가능 여부를 반드시 확인해야 한다.
핵심 용어 정리
AD
제휴 광고 · 일부 링크는 수수료를 받을 수 있습니다
iframe = 현재 페이지 안에 다른 HTML 문서를 넣는 태그
iframe 기반 SPA형 구조 = 여러 페이지를 iframe으로 불러와 하나의 앱처럼 화면을 전환하는 구조
레거시 시스템 = 오래전부터 운영되어 온 기존 시스템
SPA = 하나의 페이지 안에서 화면만 바꿔 앱처럼 동작하는 웹 애플리케이션 방식
WebView = 앱 안에서 웹 화면을 보여주는 브라우저 영역
JavaScript 라이브러리 = 자주 쓰는 기능을 미리 만들어 둔 코드 묶음
OpenCV = 이미지 처리와 컴퓨터 비전 기능을 제공하는 라이브러리
컴퓨터 비전 = 이미지나 영상에서 정보를 분석하는 기술
Konva.js = Canvas 위에 도형, 이미지, 텍스트를 쉽게 그리게 해주는 라이브러리
Canvas = 웹에서 그림이나 그래픽을 그릴 수 있는 HTML 요소
ECharts = 차트와 그래프를 그리는 JavaScript 라이브러리
공통 헤더 파일 = 여러 페이지에서 같이 사용하는 CSS, JavaScript, 설정 등을 모아 둔 파일
부모 창 = iframe을 포함하고 있는 바깥 페이지
자식 iframe = 부모 창 안에서 실행되는 iframe 페이지
window.self = 현재 코드가 실행 중인 창
window.top = 가장 바깥에 있는 최상위 창
window.parent = 현재 iframe을 감싸고 있는 부모 창
메모리 = 프로그램이 실행 중인 데이터를 임시로 저장하는 공간
중복 로딩 = 같은 파일이나 기능을 여러 번 불러오는 현상
초기화 비용 = 라이브러리를 사용할 준비를 하기 위해 필요한 처리 작업량
동기 = 앞 작업이 끝난 뒤 다음 작업을 실행하는 방식
비동기 = 앞 작업이 끝나기를 기다리지 않고 다음 작업을 실행하는 방식
postMessage = 부모 창과 iframe이 메시지를 주고받게 해주는 JavaScript 기능
도메인 = 웹사이트 주소의 기준이 되는 이름
라우팅 = URL이나 상태에 따라 어떤 화면을 보여줄지 정하는 방식
SEO = 검색엔진이 페이지를 잘 찾고 이해하도록 만드는 작업
AD









