Files
dwg-dxf-viewer-sample/docs/sample-test-report-2026-10-19.md
T
minsungandClaude Opus 5.5 ae77253229 docs: sample test and error-handling status report (2026-10-19)
Re-test of every sample in the browser viewer and headless Node, the
history of 13 handled errors with before/after/current captures for the 8
that could be reproduced, newly found issues (Fit cropping, %%% control
codes, symbol-only CP949 strings, broken e2e) and the library packaging
assessment. scripts/parse-dwg.mjs is the headless parser used for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 19:48:44 +09:00

26 KiB
Raw Blame History

샘플 테스트·오류 처리 현황 보고서 (2026-10-19)

대상: dwg-dxf-viewer-sample (HEAD 1f80442 + 미커밋 작업 트리) 근거: 이번 재테스트 실측, git 이력 20커밋, docs/*.md 10건, hmwebviewer/PROGRESS.md 상태 표기: 원인 확정 · 수정 완료·검증됨 · 수정 완료·미검증 이 보고서에는 검증된 결과만 싣는다. 검증하지 못한 항목은 §8 목록에만 적는다.


1. 핵심

  • 고유 샘플 20개(DWG 19 + DXF 1)가 모두 브라우저 뷰어에서 로드에 성공했다. 콘솔 에러는 404 리소스 1건뿐이다. Node 헤드리스 파싱도 19/19 성공했다.
  • 기존 e2e(e2e_lin_test.cjs)는 지금 상태 그대로는 실패한다 (ERR_MODULE_NOT_FOUND). 끝까지 돌려도 assert 가 없어서 결과를 판정하지 못한다.
  • 과거에 처리한 오류 13건 중 8건을 검증했다 (§4.1). 해당 커밋의 수정 전 버전과 수정 후 버전을 실제로 띄워서, 현재 버전까지 3단으로 캡처하고 측정했다.
    • 대용량 로드: 213.8초 → 3.6초
    • Slug 글자 높이: 150px → 202px (비율 0.743, 커밋 주장 0.744)
    • 레이어 토글: 454622ms → 1335ms
    • 그 외 회색 원 제거, 메쉬 표시, 선가중치 적용, Model/Paper 분리, 한글 복원
  • 이번에 새로 찾은 문제는 4건이다.
    • Fit 이 도면 가장자리를 잘라냄
    • %%% 제어코드가 변환되지 않음
    • 기호만 있는 CP949 문자열이 깨진 채 남음
    • e2e 스크립트가 고장 나 있음
  • 라이선스 2건 (원인 확정)
    • 공개한 MPL 패치를 원본 acadrust 0.4.1 에 적용하면 실패한다. 실제 wasm 의 소스를 재현할 수 없다는 뜻이다.
    • Visio 저작권("All rights reserved") 라인타입 데이터가 번들에 들어 있다.
    • Gitea 와 dist2 는 사내 전용이다. 외부 반출(고객 납품·외부 웹 공개·npm) 전에 해결해야 한다. 라이선스 고지 버튼 자체는 형식이 맞다. 그 버튼이 가리키는 패치 내용이 틀렸다.
  • 라이브러리 배포는 조건부로 가능하다 (§6). 위 라이선스 2건, Vite 전용 코드, Viewer2D 에 dispose() 가 없는 문제를 먼저 해결해야 한다.

2. 권장 액션

  1. 라이선스.
    • MPL 패치를 다시 만든다. 원본 0.4.1 과 실제 vendored 트리의 전체 diff 로 만들고, 원본에 적용해서 성공하는지 확인한다.
    • 고지 문서 4곳의 "한 파일만 수정", "unmodified" 문구를 고친다.
    • ICAD_LIN 은 IntelliCAD(ITC) 계약 범위를 확인한다. 외부 배포가 허용되지 않으면 제거한다.
  2. 미커밋 작업 정리.
    • 2.5D 보기, VIEWPORT 채움 변환, Z 붕괴 수정을 커밋하거나 분리한다.
    • 루트의 untracked 대용량 파일(C0060202.json 31.7MB, SAN01.json 16.6MB, C0060202.zip)은 .gitignore 에 넣거나 삭제한다.
  3. e2e 를 실제 테스트로.
    • linParser.ts 의 확장자 없는 import 를 고친다.
    • 샘플 경로를 dist/ 에서 public/samples/ 로 바꾼다.
    • assert 를 추가한다.
    • 이번에 쓴 브라우저 e2e 와 3단 비교 스크립트를 레포에 넣는다.
  4. Fit 잘림 수정 (§3.4-①).
  5. 텍스트 후처리 2건 수정.
    • stripMText 에 %%%, %%nnn, %%o, %%u 처리를 추가한다.
    • fixCp949Mojibake 가 한글이 없는 CP949 기호도 복원하게 한다.

3. 이번 재테스트 결과

3.1 환경

항목 값
코드 HEAD 1f80442 + 미커밋 변경(2.5D 보기, _bakeFillXf, _trimmedContentBox Z 수정)
Node v24.11.1
브라우저 시스템 Chrome headless, playwright-core@1.56.1
GPU ANGLE D3D11 / NVIDIA RTX 3060 (실제 GPU)
타입체크 npm run typecheck 통과 (컴파일 통과일 뿐, 동작 검증은 아님)

3.2 샘플별 결과

열 설명:

  • Node 파싱: parse_dwg_json + fixDwgKoreanText 실행 시간.
  • RSS: 프로세스 전체 메모리.
  • 브라우저 로드: 파일을 선택한 뒤 상태바에 ✓ <파일명> 이 뜨기까지의 시간.
  • JS heap: performance.memory.
  • notif: acadrust notification 개수.
파일 MB 버전 엔티티 Node 파싱 ms RSS MB 브라우저 로드 ms JS heap MB 콘솔 에러 notif 결과
BasicSample.dwg 0.4 R2018 7,309 142 147 553 47 1¹ 4 통과
civil.dwg² 5.4 R2000 17,810 389 264 799 98 0 2 통과
C0060203-001-표준단면도(…).dwg 0.4 R2007 2,068 93 126 567 57 0 78 통과
bb.dwg 0.7 R2018 438 75 109 579 46 0 4 통과
simple.dxf 0.0 DXF 6 — — 74 34 0 — 통과
04manhole1-simplify.dwg 0.4 R2018 7,035 118 138 575 54 0 4 통과
dwg_18.3mb.dwg 18.4 R2018 82,393 1,988 1,087 4,232 372 0 4 통과
test.dwg³ 18.4 R2018 82,393 2,156 1,088 3,914 371 0 4 통과
대산당진 2공구_노면_….dwg 37.1 R2018 65,495 3,017 1,373 5,454 782 0 4 통과
a. 거더배치 삽도 0.2 R2018 1,433 118 134 568 139 0 5 통과
a. 교대배치 삽도 0.4 R2018 2,138 58 102 565 59 0 4 통과
a. 교량시종점 삽도 0.4 R2018 4,432 84 105 542 56 0 4 통과
a. 교량폭원 삽도 0.5 R2018 2,824 64 106 575 45 0 4 통과
a. 교면포장 삽도 0.2 R2018 1,304 54 104 570 44 0 4 통과
a. 중앙분리대 삽도 0.4 R2018 2,159 63 103 537 44 0 4 통과
a. 횡단경사 삽도 0.5 R2018 5,635 126 138 569 44 0 4 통과
산외교- ELEVATION 산출근거도 0.6 R2007 11,262 162 181 937 111 0 44 통과
산외교-받침배치도 0.4 R2018 6,240 106 144 635 63 0 4 통과
산외교_파이형_교각일반도(울산P11-꺾임) 1.0 R2018 25,927 371 219 810 56 0 4 통과
산외교_파이형_교각일반도(울산P9) 1.0 R2018 26,207 397 220 744 57 0 4 통과

¹ 404 리소스 1건, 첫 페이지에서만 발생. /favicon.ico 가 404 를 반환하는 것은 확인했다. ² civil.dwg 와 C0060202-001-평면및종단면도(…).dwg 는 md5 가 같다. 같은 파일이다. ³ test.dwg 는 dwg_18.3mb.dwg 와 바이트는 다르지만, 파싱 결과의 엔티티 수와 텍스트 통계가 같다.

"통과" 의 기준: 상태바에 ✓ <그 파일명> · … entities 가 표시되고, .err 가 없고, 페이지 crash 가 없을 것.

3.3 기존 e2e (e2e_lin_test.cjs)

실행 방식 결과
node e2e_lin_test.cjs (그대로) 실패, exit 1. 4단계에서 ERR_MODULE_NOT_FOUND: …/src/viewer2d/linData
resolve hook 추가 끝까지 실행, exit 0. H-DICHL06/06R/02R/01R/05 패턴 5개 출력

원인 확정: linParser.ts 가 ./linData 를 확장자 없이 import 한다. Vite 는 이것을 해석하지만 Node ESM 은 해석하지 못한다.

그 밖의 문제:

  • assert 가 없다. 패턴을 못 찾아도 console.error 만 찍고, 마지막에 항상 COMPLETED SUCCESSFULLY 를 출력한다.
  • 샘플 경로가 gitignore 된 ./dist/samples/… 다. clean checkout 에서는 실패한다.
  • 느린 경로인 parse_dwg 를 쓰고 fixDwgKoreanText 를 적용하지 않는다. 그래서 출력되는 라인타입 설명이 LÇüÃø±¸ 처럼 깨진다.
  • Found 0 text styles 가 출력된다. tables.styles 가 비어 있다는 문서상 과제가 C0060202 에서도 재현된다.

3.4 이번에 새로 확인한 문제

① Fit 이 도면 가장자리를 잘라냄. 재현 확인.

  • ELEVATION 도면에서 Fit 을 하면 도곽 왼쪽이 화면 밖으로 나가고, 오른쪽에는 약 470px 가 비어 있다 (§4.1 캡처).
  • 자동 Fit, Fit 버튼, 창 크기 변경 후 Fit 모두 같은 결과다.
  • HEAD(미커밋 변경 제외)에서도 똑같다. WIP 회귀가 아니다.

② AutoCAD 제어코드 %%% 등이 변환되지 않음. 원인 확정.

  • C0060203 에 -2 %%%, civil Layout 에 S=0.0000%%% 가 그대로 표시된다.
  • Viewer2D.js:64 의 stripMText 는 %%d, %%p, %%c 만 처리한다.

③ 기호만 있는 CP949 문자열이 깨진 채 남음. 원인 확정.

  • civil 에 500¡¿350 이 표시된다. CP949 로 디코딩하면 500×350 이다.
  • fixDwgKoreanText.ts:64-67 는 디코딩 결과에 한글이 생길 때만 변환을 받아들인다.

④ e2e 스크립트 고장. §3.3 참고.

기타 (경미)

  • Layout 탭 이름이 Layout (Paper_Space0) 처럼 내부 블록명으로 나온다. dwg2model 삽도 7개 전부가 그렇다.
  • Layout 탭이 많으면 툴바가 줄바꿈되면서 상태바가 속성 패널과 겹친다.
  • parse_dwg_json 은 acadrust notification 의 개수만 돌려주고 내용은 돌려주지 않는다 (C0060203 78건, ELEVATION 44건).

4. 처리된 오류 이력

표기: [M] 커밋 메시지 · [D] diff 로 확인 · [Doc] 문서 기록. Rust 쪽 수정(dwg-wasm, acadrust)은 hmwebviewer/rust/dwg-wasm 에 있다.

# 시기 증상 재현 샘플 원인 조치 커밋 이번 검증
1 07-30 구형 한글 TEXT/MTEXT 깨짐 civil 외 CP949 바이트가 Latin-1 로 올라옴 [Doc] fixDwgKoreanText.ts (뷰어) be8d52f 수정 완료·검증됨 (§4.1-①)
2 07-30 Model 과 Paper 동시 렌더, Layout 비어 보임, Fit/좌표, 글자 거대, VP 순서 (6건) C0060202 VIEWPORT 미투영, minTextH 등 [Doc] cadSpaces.ts, Viewer2D (뷰어) be8d52f 수정 완료·검증됨 (§4.1-②)
3 07-30 Brave/Firefox 에서 OLE BMP 미표시 — <img> 가 data:image/bmp 미지원 [M] 순수 JS BMP 디코더 [D] 963a903 §8
4 07-30 OLE2FRAME 이 하드코딩된 좌표에 고정됨 — 정답 좌표 하드코딩 [D] 파서가 준 ul/lr 사용 76f3e20 §8
5 08-03 Slug 텍스트 cap-height 약 26% 작음 BasicSample 3d3e052 의 회귀 [D] 되돌림 fb8f7ca 수정 완료·검증됨 (§4.1-④)
6 08-03 19MB DWG 로딩 시 탭 프리즈 dwg_18.3mb wasm 힙 O(n²) [M] parse_dwg_json 스트리밍 b047dc4 수정 완료·검증됨 (§4.1-③)
7 08-03 도면 위아래 거대 회색 원 dwg_18.3mb sample_arc 각도 swap 등 [Doc] 손상 호 감지 후 생략 (파서) b047dc4 수정 완료·검증됨 (§4.1-③)
8 08-04 레이어 토글 지연 dwg_18.3mb 토글마다 load() 재빌드 [M] setDrawRange, .visible 토글 3480945 수정 완료·검증됨 (§4.1-⑦)
9 08-04 노면/부체도로면(MESH) 미표시 대산당진 노면 MESH 직렬화 누락, read_mesh 100k 상한 [M] acadrust 패치 + 직렬화 + _meshSegs eec3382, c67a803 수정 완료·검증됨 (§4.1-⑤)
10 08-04 모든 선이 1px 대산당진 노면 lineWeight 누락, WebGL linewidth 무시 [M] LineSegments2 버킷 c67a803 수정 완료·검증됨 (§4.1-⑥)
11 08-04~05 선가중치 배율 (8 → 20 → 11 px/mm) 대산당진 노면 배율 [M] 기본값 11, 옵션 패널 cf12987, a924b1e, 1f80442 굵기 적용 확인 (§4.1-⑥). 배율 일치는 §8
12 08-04 MPL-2.0 고지 누락 — 고지/원문/소스 경로 없음 [M] NOTICES, public/licenses/ ce3859c 조치 불충분: 패치가 원본에 적용되지 않음 (§5 A-1)
13 08-04 vite build 가 dist2 테스트 파일을 삭제 — emptyOutDir 기본값 [M] --emptyOutDir false 절차 문서화 6f200ef —

분리 전 hmwebviewer 에서 처리한 것 (07-10~14, PROGRESS.md):

  • solid HATCH 구멍, HIDDEN/CENTER 파선 무시
  • MAX_TEXTS 3000 상한
  • 회전 도곽 viewTwist, 로고 해치, 폴리라인 폭, MTEXT 배경

미커밋 수정 2건 (수정 완료·미검증):

  • VIEWPORT 안 SOLID/HATCH 채움에 model→paper 변환 추가 (_fillXf/_bakeFillXf)
  • _trimmedContentBox 의 Z 붕괴 수정

4.1 수정 전 / 수정 후 / 현재 비교 캡처

방법

  • 각 버전은 git archive <커밋> 으로 풀어서 실행했다. wasm 이 커밋마다 함께 커밋돼 있어서, 그 시점의 파서와 뷰어가 같이 재현된다.
  • 계측용으로 두 가지만 덧붙였다. 둘 다 동작에는 영향이 없다.
    • main.ts 에 window.__viewer = viewer 1줄
    • vite 캐시 경로 분리
  • "현재" 는 오늘의 작업 트리다.
  • 로드 판정은 상태바가 ✓ <그 파일명> · 으로 바뀌었는지로 했다.
  • 확대 화면은 모든 버전에서 같은 WCS 좌표와 화면 폭으로 카메라를 고정했다. 파일럿 캡처로 목표 객체가 화면 중앙에 오는 것을 먼저 확인했다.
  • UI 패널은 숨기고 캔버스만 찍었다. 해상도 1280×800, RTX 3060.
  • 24회 실행 모두 로드 성공, 콘솔 에러 0건.

① 한글 깨짐 (civil.dwg)

수정 전 버전의 wasm 이 실제로 내보낸 문자열과, 수정 후 화면을 함께 비교했다:

handle 수정 전 95fa6a4 wasm 출력 수정 후 be8d52f
3232403 Ãø Á¡ 측 점
3232405 °èȹ°í 계획고
3232408 Áö¹Ý°í 지반고
3240601 õÀÇ1Áö±¸ °èȹ¼± 천의1지구 계획선
3241973 (»ç¾÷ ÁøÇà ¿¹Á¤) (사업 진행 예정)
1009 °Ç¼³´Ü°è 건설단계
수정 후 be8d52f 현재

② Model/Paper 겹침, Layout 비어 보임 (civil.dwg, 로드 직후 기본 화면)

수정 전 95fa6a4 수정 후 be8d52f 현재
점 3개만 보임. Model(x≈600k·162k)과 Paper(원점)를 한꺼번에 Fit 함 Layout 이 열리고 VIEWPORT 내용이 투영됨 같음 (밝은 종이 배경)

③ 대용량 로딩 + 거대 회색 원 (dwg_18.3mb.dwg, 로드 직후 기본 화면)

수정 전 7a6edd4 수정 후 b047dc4 현재
로드 213.8초. 회색 SOLID HATCH 가 도면 아래쪽 절반을 덮음 3.6초, 회색 채움 없음 3.7초

④ Slug 텍스트 크기 (BasicSample.dwg, "정면도" h=140 주변 고정 화면)

수정 전 b047dc4 수정 후 fb8f7ca 현재
글자 높이 150px 202px 202px
  • 자홍색 픽셀 bbox 높이를 쟀다. 비율 150/202 = 0.743 으로, 커밋 메시지 "3.6 → 2.68 (0.744)" 와 일치한다.
  • 주변 선과 치수의 위치는 세 장 모두 같다.

⑤ SubDMesh(MESH) 미표시 (노면 도면, 연결부 (156542, 479804), 폭 160)

수정 전 6f200ef 수정 후 c67a803 현재
삼각망 없음 도로면·부체도로면 삼각망 표시 같음

c67a803 에는 선가중치 수정도 함께 들어 있다.

⑥ 선가중치 (⑤와 같은 화면)

수정 전 eec3382 수정 후 1f80442 (11 px/mm) 현재
0.50mm 도로마킹 포함 모든 선 1px (메쉬 렌더러 이전 버전) 굵게 표시 같음

⑦ 레이어 토글 속도 (dwg_18.3mb.dwg, setHiddenLayers(CF-PATT) 숨김→표시 3회, 동기 실행 시간)

수정 전 fb8f7ca 수정 후 3480945 현재
숨김 ms 565 / 454 / 512 18 / 17 / 13 21 / 18 / 13
표시 ms 501 / 622 / 609 26 / 5 / 6 35 / 5 / 5

새로 확인한 문제 (현재 버전)

%%% 미변환 (C0060203) CP949 기호 잔존 (civil) Fit 잘림 (ELEVATION)
-2 %%% (정답 -2 %) 500¡¿350 (정답 500×350) 왼쪽 잘림, 오른쪽 약 470px 공백

5. 남은 과제

A. 우선 처리

# 과제 근거
A-1 MPL 패치가 실제 소스를 재현하지 못함 (원인 확정)
- public/licenses/acadrust-0.4.1-read_mesh.patch 를 원본 acadrust 0.4.1 crate 에 git apply --check 하면 entities.rs:2350(read_ole2frame)에서 실패한다.
- 고지의 "One file differs", "exact Source Code Form" 문구와 acadrust-dwg/package.json 의 "used unmodified" 가 사실과 다르다.
이번 실행, THIRD-PARTY-NOTICES.md
A-2 Visio 저작권 데이터가 번들됨
- linData.ts 의 ICAD_LIN 헤더가 "Copyright (c) 1998 by Visio Corporation. All rights reserved" 다.
- linParser.ts:228 이 import 될 때 등록하므로 배포본에 반드시 들어간다.
- IntelliCAD(ITC) 계약이 자사 웹 뷰어로의 외부 배포를 허용하는지 확인이 필요하다.
이번 확인
A-3 자체 LICENSE 파일 없음, NanumGothic OFL 원문 미동봉 §6
A-4 자동 판정 테스트 없음, e2e 고장 §3.3
A-5 Fit 이 가장자리를 잘라냄 §3.4-①
A-6 미커밋 WIP 정리, src/topProgress.ts 어디서도 import 되지 않음, 루트 대용량 untracked 파일 git status
A-7 원본 hmwebviewer 에 Model/Paper 수정 미이식 (cadSpaces.ts 없음) model-paper-space.md §9

B. 기능·품질

# 과제 근거
B-1 해치 손상 호의 근본 원인 미확인. 현재 수정은 감지 후 생략. spurious_r 5배 임계값은 경험값 hatch-boundary-arc-artifact.md §7
B-2 파싱 중 메인 스레드 블로킹. 37MB 도면 로드 5.5초 동안 UI 정지. Web Worker 미적용 이번 측정
B-3 메쉬 레이어에 굵기가 지정되면 fat 버킷 상한(40만) 124.5% 초과 → 버킷 전체 헤어라인 폴백 improvement-results §5-3
B-4 %%% 등 제어코드, CP949 기호 §3.4-②③
B-5 tables.styles 비어 있음 → 폰트 매핑 불가 한글 문서 §8, 이번 e2e
B-6 한글 처리가 JS 휴리스틱. 932/936/950 미지원 한글 문서 §8
B-7 Layout 탭 캡션이 내부명 이번 실행
B-8 acadrust notification 내용 비노출 이번 실행
B-9 40만 상한 초과 시 사용자 알림 없음 (console.warn 만) lineweight-rendering.md §6
B-10 wasm32 4GB 한계. 37MB 도면에서 Node RSS 1.37GB, 브라우저 JS heap 782MB 이번 측정

C. 나중에

  • 선가중치: 중첩 ByBlock 미추적, DXF LAYER 코드 370 무시, celweight 가 DWG 인덱스 그대로 나감
  • MESH: Catmull-Clark(subdivisionLevel > 0), POLYFACE/POLYGON MESH, shaded 패스
  • VIEWPORT: 솔리드 HATCH 근사, 비직교 VP, TILEMODE/CTAB 휴리스틱
  • OLE BMP 가 24/32bpp 만 지원
  • parse_dwg export 미정리
  • CXGLOGO-EX흑백.dwg 의 얇은 원 (hmwebviewer 시절부터)

D. 배포·문서 정리

  • build:dist2 스크립트 없음, dist2/assets 에 예전 해시 번들 누적, 테스트 도면이 dist2/samples 에 섞여 있음
  • 문서 상태 표기가 낡음:
    • subdmesh-rendering.md: "렌더러 미커밋"
    • lineweight-rendering.md, improvement-results: "미푸시"
    • 여러 문서: "acadrust 미수정"
  • Viewer2D.d.ts:24, Viewer2D.js:1389 주석은 "Default 20" 인데 실제 기본값은 11
  • README 이슈 표에 hatch, large-dwg 문서 누락

6. 라이브러리 배포 가능성

6.1 결론: 조건부 가능

  • 파서는 DOM 없이 동작한다. Node 24 에서 initSync 로 19개 도면을 파싱해 실측했다.
  • Viewer2D 가 DOM 에 닿는 곳은 생성자로 받는 container 하나뿐이다.
  • 다만 아래 차단 요소를 먼저 풀어야 한다.

6.2 차단 요소

# 문제 위치 영향
L1 MPL 패치로 소스 재현 불가 §5 A-1 법적 의무 미충족
L2 Visio 저작권 lin 데이터 linData.ts:2 재배포 권리 확인 필요
L3 자체 LICENSE, package.json license 필드 없음. Viewer2D.js:3 에 "Ported from webviewer/…" 루트 사용 권리 불명확
L4 NanumGothic OFL 원문 미동봉 public/licenses/ 폰트 동봉 시 위반
B1 ?url import 가 Vite 전용 acadrustParser.ts:6 Node·webpack·SSR 에서 실패. Vite lib 모드로 빌드하면 wasm 이 base64 로 두 번 인라인됨 (실측 2.37MB)
B2 확장자 없는 상대 import dwgParser.ts:16, parseDxf.ts:7, Viewer2D.js:16-18 외 Node ESM 에서 ERR_MODULE_NOT_FOUND (§3.3 과 같은 원인)
B3 폰트 경로 /fonts/… 하드코딩, 전역 싱글톤 slugText.ts:32-49, Viewer2D.js:127 호스트에 그 경로가 없으면 404
B4 dispose() 없음 Viewer2D.js:159,164,4527 익명 window 리스너와 rAF 루프를 해제할 수 없음. F 키 리스너는 입력란에서도 Fit 실행
B5 타입 불완전 Viewer2D.d.ts load(result: unknown), 일부 메서드 누락, 기본값 주석 20 ≠ 실제 11
B6 패키지 설정 없음 package.json private: true, exports/files/peerDependencies 없음
B7 소스 정본이 여러 곳 이 레포 / hmwebviewer/src/viewer2d / hmwebviewer/packages/dwg-dxf-viewer wasm 바이너리 3개가 모두 다름. Viewer2D.js 는 hmwebviewer 와 1,217줄 차이

6.3 권장 구조: 패키지 2개

@scope/cad-parser   (headless, three 없음)        license: "MIT AND MPL-2.0"
  initDwgParser({ wasm?: URL | bytes | Module })
  parseDwg(bytes) / parseDxf(buf) / parseCad(buf, nameHint?)
  listCadSpaces, pickDefaultSpace, isDwg/isDxf, CadParseResult 타입
  ./worker  (선택: 메인 스레드 비블로킹)

@scope/viewer2d     (Viewer2D, slugText, linParser)   license: "MIT"
  peerDependencies: three ^0.185.0   ← peer + external
  dependencies:     @scope/cad-parser, opentype.js

파서 패키지 package.json 핵심:

{
  "type": "module",
  "license": "MIT AND MPL-2.0",
  "exports": {
    ".": { "types": "./dist/index.d.ts", "node": "./dist/node.js", "default": "./dist/browser.js" },
    "./worker": "./dist/worker.js",
    "./acadrust_dwg_bg.wasm": "./dist/acadrust_dwg_bg.wasm"
  },
  "files": ["dist", "licenses", "THIRD-PARTY-NOTICES.md", "LICENSE"],
  "sideEffects": false
}

wasm 로딩:

  1. 기본: glue 의 new URL('./acadrust_dwg_bg.wasm', import.meta.url) 패턴을 유지한다.
  2. 탈출구: init({ wasm }) 로 URL, bytes, Module 을 직접 넘길 수 있게 한다.
  3. Node: initSync({ module: readFileSync(...) }). scripts/parse-dwg.mjs 에서 동작을 확인했다.

6.4 작업 순서

  1. 라이선스 L1~L4 해결
  2. 정본 레포 통일, rust/dwg-wasm 과 vendored acadrust 이전, rust-toolchain.toml 로 툴체인 고정
  3. 파서 분리: ?url 제거, init({ wasm }) 추가, Node 진입점, parseCad(), 상대 import 에 .js
  4. Viewer2D: 생성자 옵션(fontUrl, keyboard 등), dispose(), ResizeObserver, localStorage 잔재 제거, 콜백 해제 함수
  5. 타입: 수기 Viewer2D.d.ts 보완, CadParseResult 구체화
  6. 빌드: tsup/rollup/tsc 로 ESM, wasm 은 파일로 복사, opentype.js 는 default import (Node ESM 에서 named import 실패 실측)
  7. 검증: 소비 예제(Vite, webpack 5, Node)를 CI 로 돌리고, §3 의 샘플 20개 e2e 를 회귀 테스트로

6.5 유의할 점

  • 크기

    파일 raw brotli
    wasm 884KB 301KB
    폰트 2.05MB 432KB

    폰트는 번들하지 말고 fontUrl 옵션으로 받는다.

  • 메모리: 37MB 도면에서 Node RSS 1.37GB, 브라우저 JS heap 782MB. wasm32 상한은 4GB 다.

  • 런타임: CSP 에 'wasm-unsafe-eval' 이 필요하다. application/wasm MIME 이 아니면 느린 폴백으로 떨어진다.

  • 한글: cp949/euc-kr TextDecoder 가 없는 런타임에서는 fixDwgKoreanText 가 아무 표시 없이 보정을 건너뛴다.

  • 버전 정책: 두 패키지는 lockstep 으로 올린다. CadParseResult 필드 추가는 minor, 삭제나 변경은 major.

  • upstream drift: README 의 "본가에서 다시 복사" 절차를 따르면 이 레포의 기능(lineweight, 2.5D, Model/Layout)이 지워진다.

  • acadrust 버전: 상류는 0.6.x 다. 0.4.1 fork 유지 여부를 결정해야 한다.

  • 릴리스: 깨끗한 태그에서만 배포한다.


7. 재현 방법

# 헤드리스 파싱 (1개 파일)
node scripts/parse-dwg.mjs "<file.dwg>" [out.json]

# 기존 e2e (현재는 실패, §3.3)
node e2e_lin_test.cjs

배치 파서, 브라우저 e2e, 3단 비교 캡처 스크립트는 세션 임시 폴더에 있다. 레포 반영은 §2-3. 측정 원본은 images/sample-test-2026-10-19/results.json 에 있다.

8. 검증 불가 목록

항목 이유
OLE BMP(#3), OLE2FRAME(#4) OLE2FRAME 엔티티가 있는 샘플이 없음
선가중치 배율(#11)이 AutoCAD 와 일치하는지 같은 위치의 AutoCAD 정답 캡처가 없음
한글 깨짐(#1) 수정 전 화면 같은 커밋에서 고친 '글자 거대' 버그 때문에 판독 불가. 문자열 비교로 대신 검증함
수정 전 수치와 문서 기록의 차이 (로드 213.8s vs 문서 354s, 토글 약 0.5s vs 커밋 "5초 이상") 당시 측정 환경과 방법을 알 수 없음
Fit 잘림의 원인 재현만 확인, 원인 미확정
H-DICHL06 의 patternLen(1) 과 요소 합(1.588) 중 어느 쪽이 AutoCAD 기준인지 AutoCAD 대조 수단 없음
문서상 한글 재현 도면 C0060203-002-굴착및시공순서도.dwg 레포에 없음
7~8월 테스트 당시의 증상 원문 세션 기록이 남아 있지 않음 (가장 오래된 기록이 09-16)