GITHUB 레포 딥다이브 · 2026-07-29 · XUSHANPEI/OPEN-FILE-VIEWER · 웹용 만능 파일 미리보기 SDK

xushanpei/open-file-viewer 딥다이브
50가지 파일을 한 컨테이너에 띄우는 프리뷰 엔진

open-file-viewer는 PDF·워드·엑셀·이미지·영상·압축파일·이메일·3D·CAD·지도(GIS)·소스코드까지 수십 가지 파일 형식을 웹 페이지 안에서 그대로 미리보기 해주는 프론트엔드 SDK다. 핵심 아이디어는 두 가지 — ① 새 창을 띄우지 않고 네가 지정한 DOM 컨테이너 안에 렌더링하고, ② 순수 JavaScript·React·Vue·Svelte를 하나의 코어로 전부 지원한다.

파일 형식마다 렌더링 방법이 다른데(PDF는 pdf.js, 워드는 mammoth, 엑셀은 SheetJS, 3D는 three.js…), 이 프로젝트는 형식별로 독립된 플러그인을 만들고 "매치되는 첫 플러그인이 그린다"는 아주 단순한 레지스트리로 묶었다. 게다가 필요할 때만 라이브러리를 import()로 지연 로딩해서, 안 쓰는 형식의 무거운 코드는 번들에 실리지 않는다. "라이브러리를 어떻게 프레임워크에 안 묶이게 설계하는가"를 배우기에 교과서 같은 레포다.

(저장소 xushanpei/open-file-viewer · 언어 TypeScript · 라이선스 MIT · 버전 0.1.32 · 구조 pnpm 모노레포(core + react/vue/svelte 바인딩) · 코어 소스 ~5만 줄 · 최신 커밋 2026-07-27 · npm @open-file-viewer/core · 제작 xushanpei · 성숙도 0.1.x 초기 단계)
목차
  1. 한 줄 정체
  2. 왜 주목받는가 — "미리보기"라는 오래된 골칫거리
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 — 코어·플러그인·프레임워크 바인딩
  5. 디렉토리 구조 해부
  6. 학습 포인트 — 기술별 배울 것
  7. 시스템 / 브라우저 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 로드맵 (주차별)
  10. 핵심 키워드 사전
  11. 참고 링크

1한 줄 정체

이 레포가 정확히 무엇인지 한 문장으로

open-file-viewer는 "브라우저 안에서 아무 파일이나 미리보기 창을 띄워주는 부품(SDK)"이다. 네가 만드는 웹 앱에 이 라이브러리를 붙이면, 사용자가 올린 .pdf·.docx·.xlsx·.png·.mp4·.zip·.eml·.glb(3D)·.dwg(CAD)·.geojson(지도) 파일을 새 탭으로 나가지 않고 페이지 안 지정된 자리에 그려준다.

비유로 이해하기

공항의 만능 X-ray 검색대를 떠올려 보자. 가방(파일)이 어떤 종류든 — 캐리어든, 배낭이든, 악기 케이스든 — 같은 벨트에 올리면 안이 화면에 뜬다. open-file-viewer가 하는 일이 딱 이것이다. "이 파일이 무슨 형식이지?"를 먼저 판별하고(detect), 형식에 맞는 전용 렌더러(플러그인)에게 넘겨 화면에 그린다.

핵심은 벨트는 하나라는 점이다. 형식이 50개여도 사용자가 쓰는 API는 createViewer({ container, file }) 딱 하나다.

기술적으로 정리하면 세 층이다. ① 코어(@open-file-viewer/core) — 순수 DOM만 다루는 프레임워크 무관 엔진. ② 플러그인 20종 — 형식별 렌더링 로직(image / pdf / office / archive / 3d / cad / gis …). ③ 프레임워크 바인딩 3종(react / vue / svelte) — 코어를 각 프레임워크의 컴포넌트로 감싼 얇은 래퍼. 순수 JS만 쓸 거면 바인딩 없이 코어를 직접 부르면 된다.

용어
SDK (Software Development Kit)
완성된 앱이 아니라, 다른 개발자가 자기 앱에 끼워 넣는 부품 묶음. open-file-viewer는 "미리보기 기능"이라는 부품을 파는 셈이고, 그래서 UI 전체가 아니라 "컨테이너 안에 그리는 엔진"만 제공한다.

2왜 주목받는가 — "미리보기"라는 오래된 골칫거리

트렌딩 이유와 경쟁 제품 대비 강점

파일 미리보기는 "쉬워 보이지만 실제로는 지옥"인 대표적 문제다. 웹 브라우저가 기본으로 보여줄 수 있는 건 이미지·영상·PDF 정도뿐이다. 워드·엑셀·PPT·한글 문서·CAD·3D 모델은 브라우저가 전혀 모른다. 그래서 대부분의 서비스는 이렇게 때운다:

open-file-viewer의 매력은 이 세 번째 길을 한 번만 잘 배선해서 재사용 가능하게 포장했다는 것이다. 게다가 최근 흐름과 정확히 맞물린다:

주목 포인트 ①

컨테이너 우선(Container-first) — 새 창을 안 띄운다

대부분의 뷰어는 window.open()으로 새 탭을 열거나 전체화면 모달을 강제한다. open-file-viewer는 네가 준 <div> 안에 그린다. 덕분에 "왼쪽엔 파일 목록, 오른쪽엔 미리보기" 같은 앱 레이아웃을 자연스럽게 짤 수 있다. 이건 문서에만 있는 약속이 아니라 코드로 강제된다 — 플러그인은 ctx.viewport(주어진 자리)에만 그리도록 규약이 잡혀 있다.

주목 포인트 ②

프레임워크 중립 — 하나의 코어, 네 가지 사용법

React·Vue·Svelte·순수 JS를 같은 코어 엔진으로 지원한다. 회사가 Vue를 쓰든 React를 쓰든 같은 기능을 쓴다. 라이브러리 설계 관점에서 "로직은 프레임워크 밖에, 프레임워크는 얇은 껍데기"라는 이상적 구조의 실물 예제다.

주목 포인트 ③

플러그인 + 지연 로딩 — 안 쓰는 형식은 번들에 안 실린다

3D 렌더링용 three.js는 수백 KB다. 하지만 사용자가 3D 파일을 열기 전까지는 다운로드되지 않는다 — 코드가 await import("three")필요한 순간에만 불러오기 때문이다. 형식별 플러그인이 독립적이라 이런 코드 분할이 깔끔하게 된다.

한 문장 요약

"파일 미리보기"라는, 모두가 겪지만 아무도 깔끔하게 못 푸는 문제를 컨테이너 우선 + 플러그인 + 프레임워크 중립이라는 세 원칙으로 정리한 게 인기 이유다. AI 코딩 에이전트가 파일을 다루는 앱을 많이 만들면서 "만능 뷰어" 수요도 커졌다.

솔직한 한계
아직 0.1.x — "인식은 되지만 고화질은 아직"

버전이 0.1.32다. 로드맵상 CAD·3D·고급 오피스는 "인식 + 기본 미리보기" 수준이고, 고정밀 렌더링은 서버 변환이나 상용 SDK로 넘긴다고 제작자가 스스로 명시한다. 프로덕션에 넣기 전엔 네가 쓸 형식이 실제로 얼마나 잘 그려지는지 반드시 직접 테스트해야 한다. 별(star) 수도 아직 적다 — 신생 프로젝트다.

3기술 스택 전체 지도

무엇으로 만들어졌나 — 빌드 도구부터 렌더링 라이브러리까지

모노레포 & 빌드 도구

역할기술메모
패키지 매니저pnpm 11.7 (workspaces)turbo/nx 없이 순수 pnpm 워크스페이스. packages/* + examples/* + doc
번들러tsup (esbuild 기반)core/react/vue를 ESM+CJS 동시 출력 + .d.ts 타입 + 소스맵
Svelte 패키징@sveltejs/packageSvelte만 svelte-package로 별도 빌드
예제·문서 앱Vite 64개 예제 + 문서 사이트 모두 Vite dev 서버
테스트Vitest 4 + jsdomrender-smoke.test.ts가 5,900줄 — 형식별 렌더 스모크 테스트가 두껍다
언어TypeScript 5.7strict, moduleResolution: Bundler, target ES2021

형식별 렌더링 라이브러리 (핵심 의존성 지도)

이 표가 이 레포의 진짜 알맹이다. "어떤 형식을 무슨 라이브러리로 그리는가"를 한눈에 보여준다. 거의 전부 import()로 지연 로딩된다.

형식군플러그인렌더링 라이브러리
이미지imagenative <img>, TIFF=utif, HEIC=heic2any
영상/오디오video / audionative <video>/<audio>, HLS(m3u8)=hls.js
텍스트/코드text하이라이트=prismjs(언어별 청크), 마크다운=marked, 다이어그램=mermaid, 살균=dompurify
PDF/전자책pdf / epub / xpspdfjs-dist(선택적 peer), epub/xps는 jszip 해제 후 자체 렌더
오피스office / msdocdocx=docx-preview/mammoth, 엑셀=xlsx(SheetJS), pptx=@aiden0z/pptx-renderer, 구형 .doc/.xls=자체 파서
압축archivejszip, gzip=pako, bz2=seek-bzip, xz=xz-decompress
이메일emaileml/mbox=postal-mime, Outlook .msg=@kenjiuno/msgreader
3Dmodel3dthree + 예제 로더들(GLTF/OBJ/STL/FBX/PLY/3MF/USD) + OrbitControls
CADcad / cad-dwgDXF=자체 파서+pako, DWG=@mlightcad/libredwg-web(WASM, 선택적)
지도(GIS)gis지도=leaflet, kml/gpx=@mapbox/togeojson, topojson, 셰이프파일=shpjs
기타 자산assetPSD=ag-psd, Parquet=hyparquet, 그 외 메타데이터 인식
용어
선택적 peerDependency (optional peer)
"쓰려면 네가 따로 설치해" 방식의 의존성. pdfjs-dist와 DWG용 WASM은 optional peer라, PDF나 CAD를 안 쓰는 사용자는 이 무거운 패키지를 설치할 필요가 없다. 라이브러리 용량을 사용자 선택에 맡기는 영리한 방식.
용어
DOMPurify (살균/sanitize)
HTML 안에 숨은 <script>나 악성 속성을 제거해 XSS 공격을 막는 라이브러리. 워드·마크다운·이메일은 결국 HTML로 변환되는데, 남이 준 파일을 그대로 화면에 넣으면 위험하다. 그래서 렌더 전에 반드시 DOMPurify로 걸러낸다.

4아키텍처 심화 — 코어·플러그인·프레임워크 바인딩

시스템이 어떻게 맞물려 돌아가는가 (구조도 + 핵심 패턴)

전체 흐름 한 장

┌──────────────────────────────────────────────────────────────┐ │ 네 앱 (React / Vue / Svelte / 순수 JS) │ │ └─ createViewer({ container, file 또는 files, plugins }) │ └───────────────────────────┬──────────────────────────────────┘ │ (프레임워크 바인딩은 여기까지만 관여) ▼ ┌──────────────────────────────────────────────────────────────┐ │ CORE ─ viewer.ts │ │ │ │ 1) detect(file) 확장자 + MIME 으로 형식 판별 │ │ 2) findPlugin() 플러그인 배열을 위→아래로 훑어 │ │ "처음 match 되는 놈"을 채택 (순서 중요) │ │ 3) plugin.render(ctx) 선택된 플러그인이 ctx.viewport 에 그림 │ │ 4) renderToken 파일이 바뀌면 이전 렌더는 취소 │ │ 5) ResizeObserver 컨테이너 크기 변하면 다시 배치 │ └───────┬───────────────────────────────┬──────────────────────┘ │ │ ▼ ▼ ┌───────────────┐ ┌────────────────────────────────────────┐ │ .ofv-status │ │ .ofv-viewport ← 플러그인이 그리는 자리 │ │ 로딩/에러/미지원│ │ pdfPlugin → pdf.js canvas │ └───────────────┘ │ officePlugin → docx-preview / SheetJS │ │ model3dPlugin → three.js WebGL │ │ fallbackPlugin → 다운로드 링크 (항상 끝)│ └────────────────────────────────────────┘

핵심 패턴 ① — "첫 매치가 이긴다" 플러그인 레지스트리

레지스트리라고 하면 복잡한 등록 시스템을 상상하지만, 여기선 그냥 배열을 순서대로 훑는 for 루프다. 놀랍도록 단순하다.

// viewer.ts — 사용자가 준 플러그인 + 항상 마지막에 fallback
const plugins = [...(options.plugins || []), fallbackPlugin()];
const plugin = await findPlugin(plugins, file);

async function findPlugin(plugins, file) {
  for (const plugin of plugins) {
    if (await plugin.match(file)) {   // 이 형식 내가 그릴 수 있어?
      return plugin;                    // 응 → 채택하고 종료
    }
  }
  return fallbackPlugin();               // 아무도 못 그림 → 다운로드 안내
}
함정 주의
플러그인 순서가 결과를 바꾼다

"첫 매치가 이긴다"이므로 배열에 넣는 순서가 곧 우선순위다. 예를 들어 .csv를 표로 보고 싶으면 officePlugin()textPlugin()보다 앞에 놔야 한다. 순서가 반대면 텍스트 플러그인이 먼저 낚아채 그냥 글자로 보여준다. README도 이 점을 명시적으로 경고한다.

핵심 패턴 ② — 플러그인 계약(interface)은 딱 두 가지 질문

플러그인이 지켜야 할 규약은 types.ts에 있고, 요구하는 건 단 둘 — "이 파일 네가 맡을래?(match)"와 "그럼 그려줘(render)"뿐이다.

interface PreviewPlugin {
  name: string;
  match:  (file) => boolean | Promise<boolean>;      // 담당 판별
  render: (ctx)  => PreviewInstance | Promise<…>;      // 실제 그리기
}
interface PreviewInstance {
  resize?:  (size) => void;      // 컨테이너 크기 변하면
  command?: (cmd)  => void;      // 확대·회전 같은 툴바 명령
  destroy:  () => void;         // 정리(메모리 해제)
}

이렇게 계약을 좁게 잡으면 누구나 새 형식 플러그인을 쉽게 추가할 수 있다. "한글(.hwp) 플러그인"을 만들고 싶다면 match에서 확장자를 검사하고 render에서 그려 배열에 끼우면 끝이다.

핵심 패턴 ③ — renderToken으로 "빨리 넘기기" 경쟁 상태 막기

여러 파일을 빠르게 넘길 때 문제가 생긴다. A파일 렌더링(비동기)이 끝나기 전에 사용자가 B로 넘기면, 뒤늦게 끝난 A가 B 위에 덮어 그려버린다. 해결책은 단조 증가 토큰이다.

let renderToken = 0;
async function renderFile(file) {
  const token = ++renderToken;         // 이번 렌더의 번호표
  const instance = await plugin.render(ctx);
  if (destroyed || token !== renderToken) return;  // 번호표 낡음 → 버림
  // 여기 왔으면 "내가 최신" → 화면에 반영
}

핵심 패턴 ④ — 프레임워크 바인딩은 "생성/파괴 3줄"

React·Vue·Svelte 바인딩이 하는 일은 똑같다: ① <div> ref 만들고 ② 마운트되면 createViewer() 호출 ③ 언마운트/prop 변경 시 destroy(). React 예시(툴바 배선 생략):

function FileViewer({ width="100%", height="600px", ...options }) {
  const containerRef = useRef(null);
  const viewerRef = useRef(null);
  useEffect(() => {
    if (!containerRef.current) return;
    viewerRef.current?.destroy();
    viewerRef.current = createViewer({          // ← 코어 호출
      ...options, container: containerRef.current, width, height,
    });
    return () => { viewerRef.current?.destroy(); };  // 정리
  }, [options.file, options.files, width, height /* …모든 prop… */]);
  return <div ref={containerRef} />;             // 코어가 그릴 빈 자리
}
비유

코어는 발전기, 프레임워크 바인딩은 콘센트 어댑터다. 발전기(로직)는 하나뿐이고, 나라(프레임워크)마다 플러그 모양만 다르니 얇은 어댑터만 갈아 끼운다. 그래서 React 어댑터가 20~30줄로 끝난다.

숨은 보석 — 마이크로 프론트엔드 sandbox 버그 우회

이 레포에서 가장 "실전 냄새 나는" 코드가 sandbox-compat.ts다. qiankun·micro-app·wujie 같은 마이크로 프론트엔드 환경에선 zip 기반 미리보기(docx/xlsx/pptx/epub)가 영원히 "로딩 중"에 멈추는 악명 높은 버그가 있다.

원인: JSZip이 내부적으로 쓰는 setImmediate 폴리필은 windowmessage 이벤트에 의존한다. 그런데 마이크로 프론트엔드 sandbox가 앱을 정리하면서 이 리스너를 떼어버려, JSZip.loadAsync가 절대 완료 콜백을 안 부른다.

해결: sandbox를 감지하면(__POWERED_BY_QIANKUN__ 등) MessageChannel 기반의 자체 setImmediate를 심는다. 이 채널의 포트는 모듈 내부에 숨어 있어 sandbox가 건드릴 수 없다. 남이 겪은 삽질을 라이브러리가 대신 막아주는, 프로덕션 라이브러리다운 배려다.

5디렉토리 구조 해부

어느 폴더에 무엇이 있는가
open-file-viewer/ ├─ packages/ │ ├─ core/ ← 심장부 (프레임워크 무관) │ │ └─ src/ │ │ ├─ viewer.ts createViewer() · 렌더 루프 · 레지스트리 (1,526줄) │ │ ├─ detect.ts 확장자↔MIME 매핑 (형식 판별의 사전) │ │ ├─ types.ts PreviewPlugin / PreviewInstance 계약 │ │ ├─ dom.ts DOM 헬퍼 │ │ ├─ sandbox-compat.ts 마이크로 프론트엔드 setImmediate 우회 │ │ ├─ style.css 뷰어 기본 스타일 (dist로 복사됨) │ │ └─ plugins/ ← 형식별 렌더러 20종 │ │ ├─ image.ts (1,073) video.ts audio.ts text.ts │ │ ├─ pdf.ts epub.ts xps.ts │ │ ├─ office.ts (5,536!) msdoc.ts (1,847) ofd.ts (1,227) │ │ ├─ archive.ts email.ts drawing.ts (1,671) │ │ ├─ cad.ts (2,714) cad-dwg.ts model3d.ts │ │ ├─ gis.ts asset.ts (3,223) encrypted.ts │ │ └─ fallback.ts ← 항상 마지막, 다운로드 안내 │ ├─ react/ src/index.tsx React 바인딩 (얇음) │ ├─ vue/ src/index.ts Vue 바인딩 │ └─ svelte/ src/OpenFileViewer.svelte ├─ examples/{vanilla,react,vue,svelte}/ 실행 가능한 데모 4종 ├─ doc/ 문서 사이트 + LibreDWG WASM 바이너리 ├─ scripts/ check-package-exports.mjs · copy-file.mjs ├─ pnpm-workspace.yaml packages/* examples/* doc └─ README.{md,zh-CN,ja,ko,es,pt-BR}.md ← 한국어 README도 이미 있음!

코드 무게중심이 어디인지 줄 수가 말해준다. office.ts5,536줄로 압도적이다 — 오피스 문서가 그만큼 지옥이라는 방증이다. 그다음이 asset.ts(3,223), cad.ts(2,714). 테스트도 두껍다 — render-smoke.test.ts가 5,900줄로, "형식별로 실제 렌더가 깨지지 않는가"를 집요하게 검증한다.

읽기 팁
이 레포를 처음 읽는다면 이 순서로

types.ts(계약이 뭔지) → ② viewer.tscreateViewer·findPlugin(엔진이 어떻게 도는지) → ③ 가장 단순한 plugins/image.ts(플러그인 한 개가 어떻게 생겼는지) → ④ packages/react/src/index.tsx(바인딩이 얼마나 얇은지). 이 4개만 읽으면 전체 설계가 손에 잡힌다. office.ts는 나중에.

6학습 포인트 — 기술별 배울 것

이 레포를 뜯으면 실제로 뭘 배우나

① 라이브러리 설계 — "프레임워크에 안 묶이는 코어"

가장 값진 교훈. 로직을 순수 DOM/함수로 짜고(createViewer), 프레임워크는 얇게 감싼다. 이러면 React가 죽어도 코어는 산다. 오픈소스 라이브러리를 만들 계획이 있다면 이 3층 구조가 표준 답안이다.

② 플러그인 아키텍처 & 인터페이스 최소화

match/render 딱 두 메서드로 확장 포인트를 잡는 법. "인터페이스를 좁게 잡을수록 확장은 쉬워진다"를 코드로 체득한다.

③ 동적 import() 기반 코드 분할

three, pdfjs-dist 같은 무거운 의존성을 쓰는 순간에만 불러오는 실전 패턴. 초기 번들을 작게 유지하는 프론트엔드 성능 최적화의 핵심 기술.

④ 비동기 경쟁 상태(race condition) 다루기

renderToken으로 "낡은 작업 버리기". 빠른 사용자 입력 + 비동기 작업이 만나는 모든 UI에서 재사용 가능한 패턴이다(검색 자동완성, 탭 전환 등).

⑤ 파일 포맷의 실체

docx·xlsx·pptx·epub·ofd·kmz가 사실은 전부 zip 껍데기라는 것, PDF는 pdf.js가 canvas에 그린다는 것, 3D는 WebGL이라는 것 — 파일 포맷의 내부를 들여다보는 드문 기회.

⑥ 보안(XSS)과 살균

남이 준 문서를 화면에 넣기 전 dompurify로 거르는 습관. 사용자 콘텐츠를 다루는 모든 웹 개발자의 필수 반사신경.

실습 아이디어 (짧게)

7시스템 / 브라우저 요구사항

돌리려면 무엇이 필요한가
항목요구
런타임모던 브라우저(ES2021+). 서버가 필요 없는 100% 클라이언트 라이브러리 — 파일이 서버로 안 나간다(프라이버시 강점)
개발 환경Node.js + pnpm 11. pnpm i && pnpm dev:react 로 예제 실행
프레임워크React ≥18, Vue ≥3, Svelte ≥4, 또는 순수 JS(바인딩 불필요)
선택 설치PDF 보려면 pdfjs-dist, DWG(CAD) 보려면 LibreDWG WASM — 안 쓰면 설치 불필요
무거운 형식3D(three.js)·CAD는 WebGL/WASM을 쓰므로 저사양 기기에선 버벅일 수 있음
강점
전부 브라우저 안에서 — 파일이 밖으로 안 나간다

서버 변환도, 외부 뷰어도 없다. 사내 기밀 문서를 미리보기 해도 파일이 사용자 브라우저를 떠나지 않는다. 이게 구글/MS 뷰어 대비 결정적 차별점이다.

8직접 해볼 수 있는 실습 과제

난이도별 — 손으로 익히기
난이도 ★☆☆

1. 4대 프레임워크 예제 전부 띄워 보기 30분

pnpm idev:vanilla, dev:react, dev:vue, dev:svelte를 차례로 실행. 같은 파일을 네 앱에 넣어 결과가 동일한지 확인. "코어 하나, 껍데기 넷"을 눈으로 체감하는 것이 목표.

난이도 ★☆☆

2. detect.ts 읽고 판별 로직 추적 40분

.csv 파일 하나를 넣고, officePlugintextPlugin 순서를 바꿔가며 결과가 표↔글자로 달라지는지 실험. "첫 매치가 이긴다"를 손으로 검증.

난이도 ★★☆

3. 나만의 형식 플러그인 만들기 2~3시간

image.ts를 템플릿 삼아 .env.ini 파일을 키=값 표로 예쁘게 보여주는 플러그인을 작성. match(확장자 검사)와 render(ctx.viewport에 테이블 생성)만 채우면 됨. 플러그인 계약을 진짜로 이해했는지 확인하는 과제.

난이도 ★★☆

4. 코드 분할 증명하기 1시간

빌드 후 번들 분석. 3D/CAD/오피스 청크가 초기 로드에 없다가 해당 파일을 열 때만 네트워크 요청되는 걸 캡처. 지연 로딩이 실제로 작동함을 데이터로 보이기.

난이도 ★★★

5. 툴바 커스터마이징 + 다중 파일 큐 반나절

files 배열로 여러 파일을 넣고 next()/previous()/goTo()로 넘기는 갤러리 UI를 구현. 각 프레임워크의 툴바 슬롯에 자체 버튼(예: 즐겨찾기)을 꽂아 코어↔프레임워크 브리지가 어떻게 동작하는지 파헤치기.

9관련 기술 심화 로드맵 (주차별)

이 레포를 발판으로 어디까지 갈 수 있나
주차주제할 것
1주TypeScript 라이브러리 기초tsup로 ESM+CJS+타입을 동시 출력하는 법, exports 맵, peerDependency 개념
2주플러그인/전략 패턴이 레포의 레지스트리를 모방해 작은 "만능 파서" 직접 설계
3주브라우저 파일 APIFile/Blob/ArrayBuffer, FileReader, MIME 판별, JSZip으로 zip 해제
4주렌더링 라이브러리pdf.js(canvas), SheetJS(엑셀 파싱), mammoth(docx→html) 각각 단독 실습
5주three.js / WebGLGLTF 로더로 3D 모델 띄우기, OrbitControls
6주성능 & 코드 분할동적 import, 번들 분석, 지연 로딩 전략
7주프론트엔드 보안XSS, DOMPurify, CSP, 신뢰할 수 없는 콘텐츠 렌더링
8주마이크로 프론트엔드qiankun/wujie sandbox 원리, sandbox-compat.ts가 푼 버그 재현·이해

10핵심 키워드 사전

이 문서에 나온 용어 총정리
용어
SDK / 라이브러리
다른 개발자가 자기 앱에 끼워 쓰는 부품. open-file-viewer는 "미리보기 엔진"을 부품으로 제공한다.
용어
모노레포 (monorepo)
여러 패키지(core·react·vue·svelte·예제)를 한 저장소에서 관리하는 방식. pnpm workspaces가 이를 묶는다.
용어
플러그인 / 레지스트리
형식별 렌더러가 플러그인. 레지스트리는 이들을 순서대로 훑어 "처음 매치되는 놈"을 고르는 배열.
용어
프레임워크 바인딩
코어(순수 로직)를 React/Vue/Svelte 컴포넌트로 감싼 얇은 어댑터. 생성·파괴만 담당.
용어
코드 분할 / 동적 import
await import("three")처럼 필요할 때만 코드를 불러와 초기 번들을 작게 유지하는 기법.
용어
peerDependency (optional)
"쓰려면 네가 따로 깔아" 방식 의존성. 안 쓰는 무거운 라이브러리(pdf.js 등)를 강제로 설치시키지 않는다.
용어
race condition (경쟁 상태)
비동기 작업들의 완료 순서가 꼬여 낡은 결과가 최신을 덮는 문제. renderToken으로 해결.
용어
XSS / DOMPurify
문서 속 악성 스크립트가 실행되는 공격(XSS). DOMPurify로 살균해 막는다.
용어
마이크로 프론트엔드 (qiankun 등)
한 페이지에 여러 앱을 조립하는 아키텍처. sandbox가 이벤트 리스너를 정리하며 JSZip을 멈추는 버그를 이 레포가 우회한다.
용어
컨테이너 우선 (container-first)
새 창·모달을 강제하지 않고, 개발자가 준 DOM 요소 안에 렌더링하는 설계 철학.

11참고 링크

더 파고들 곳