prisma, kysely, ts-pattern, hotscript와 같은 무거운 TypeScript 의존성들도 포함되어 있었습니다.@types 선언 포함).$ tsc --listFilesOnly$ tsc --explainFiles > explanations.txttsconfig의 include/exclude/types/typeRoots/paths 설정을 조정하십시오.tsc --extendedDiagnostics. 이 명령을 실행하면 다음과 같은 출력을 얻게 됩니다(컴파일에 여러 TypeScript 프로젝트가 포함된 경우 보고서가 여러 개 보일 수 있습니다).지표 | 값 |
|---|---|
Files | 6 |
Lines | 24,906 |
Nodes | 112,200 |
Identifiers | 41,097 |
Symbols | 27,972 |
Types | 8,298 |
Memory used | 77,984K |
Assignability cache size: | 33,123 |
Identity cache size | 2 |
Subtype cache size | 0 |
I/O Read time | 0.01s |
Parse time | 0.44s |
Program time | 0.45s |
Bind time | 0.21s |
Check time | 1.07s |
transformTime time | 0.01s |
commentTime time | 0.00s |
I/O Write time | 0.00s |
printTime time | 0.01s |
Emit time | 0.01s |
Total time | 1.75s |
tsc --generateTrace <output_dir> (TypeScript 4.1부터 사용 가능). 이 명령 실행에 문제가 있다면, -f 인자(빌드 모드용)를 전달하거나 --incremental false(일반 컴파일용)를 사용하여 증분 빌드를 수행하지 않도록 설정하십시오.tsc를 빌드 모드(-b)로 실행하는지 여부에 따라 출력이 약간 다를 수 있지만, 어느 쪽이든 types와 trace에 대한 하나 이상의 JSON 파일이 생성됩니다. 시작점으로 가장 큰 파일을 찾거나, 더 완전한 설명을 위해 이 문서를 확인하십시오.about://tracing에서 사용 가능)로 분석할 수 있습니다. 더 최신 도구인 Perfetto UI를 시도해 볼 수도 있지만, 저는 예전 방식이 더 효과적이었습니다.tsc가 힙 메모리 부족(Heap Out of Memory) 오류로 실패함node 프로세스(버전 12 이후)는 시스템의 가용 메모리에 따라 최대 힙 크기가 결정됩니다. 많은 현대적 시스템에서 이는 약 2GB로 기본 설정됩니다. 메모리 관련 오류가 발생하면 node에 플래그를 전달하여 허용되는 최대 메모리 사용량을 높일 수 있습니다(이 명령은 한 번의 컴파일 실행 동안 확장 진단과 트레이스 파일 생성을 모두 수행합니다).$ node --max-old-space-size=8192 ./node_modules/.bin/tsc -b --extendedDiagnostics --generateTrace ./ts-traceabout://tracing이나 Perfetto UI 같은 도구들이 처리를 거부할 정도일 수 있습니다. 저의 경우 일부 트레이스 파일이 그랬고, 결국 이를 이해하기 위해 @typescript/analyze-trace에 의존하게 되었습니다.process-tracing 스크립트가 아무것도 출력하지 않음process-tracing 스크립트 사용을 제안합니다. 실제로 제가 시도했을 때 이 스크립트는 빈 파일만 출력했습니다. 결과는 상황에 따라 다를 수 있습니다(YMMV).$ npx analyze-trace ./ts-traceAnalyzed /<client>/<project>/packages/<package>/tsconfig.json (trace.12493-5.json)Hot Spots├─ Check file [35m/<client>/<project>/packages/<package>/src/tasks/extractions/common.ts (80609ms)│ └─ Check deferred node from (line 10, char 10) to (line 29, char 4) (80608ms)│ └─ Check expression from (line 11, char 12) to (line 28, char 7) (80607ms)│ └─ Check expression from (line 11, char 15) to (line 28, char 6) (80607ms)│ ├─ Check expression from (line 13, char 7) to (line 27, char 8) (51716ms)│ │ └─ Check expression from (line 14, char 9) to (line 26, char 12) (51711ms)│ │ ├─ Check expression from (line 24, char 18) to (line 25, char 69) (38423ms)│ │ │ └─ Check expression from (line 25, char 13) to (line 25, char 69) (38422ms)│ │ │ └─ Check expression from (line 25, char 44) to (line 25, char 68) (14922ms)│ │ └─ Check expression from (line 14, char 9) to (line 24, char 17) (13287ms)│ │ └─ Check expression from (line 14, char 9) to (line 23, char 12) (13287ms)│ │ └─ Check expression from (line 14, char 9) to (line 17, char 21) (13262ms)│ │ └─ Check expression from (line 14, char 9) to (line 16, char 42) (13261ms)│ │ └─ Check expression from (line 16, char 19) to (line 16, char 41) (4364ms)│ └─ Check expression from (line 12, char 7) to (line 12, char 32) (28891ms)└─ Check file /<client>/<project>/packages/<package>/src/tasks/transforms/operation.ts (712ms) └─ Check expression in /<client>/<project>/packages/<package>/src/tasks/extractions/operation.ts from (line 46, char 50) to (line 46, char 57) (611ms) └─ Check expression from (line 48, char 17) to (line 191, char 10) (502ms) └─ Check expression from (line 48, char 17) to (line 190, char 19) (502ms) └─ Check expression from (line 48, char 17) to (line 190, char 13) (500ms) └─ Check expression from (line 48, char 17) to (line 188, char 4) (500ms) └─ Check expression from (line 168, char 10) to (line 187, char 6) (322ms) └─ Check expression from (line 169, char 5) to (line 187, char 6) (322ms) └─ Check expression from (line 169, char 15) to (line 186, char 59) (321ms) └─ Check expression from (line 170, char 7) to (line 186, char 59) (321ms) └─ Check expression from (line 170, char 7) to (line 186, char 18) (320ms) └─ Check expression from (line 170, char 7) to (line 185, char 63) (320ms) └─ Check expression from (line 170, char 7) to (line 185, char 18) (320ms) └─ Check expression from (line 170, char 7) to (line 184, char 10) (320ms) └─ Check expression from (line 170, char 7) to (line 180, char 18) (319ms) └─ Check expression from (line 170, char 7) to (line 179, char 10) (319ms) └─ Check expression from (line 170, char 7) to (line 174, char 18) (317ms) └─ Check expression from (line 170, char 7) to (line 173, char 55) (317ms) └─ Check expression from (line 170, char 7) to (line 173, char 18) (316ms) └─ Check expression from (line 170, char 7) to (line 172, char 40) (316ms)Check deferred node from (line 10, char 10) to (line 29, char 4) (80608ms). 이는 우리가 확인해 볼 라인과 컬럼 번호를 제공합니다. 이 문맥에서 deferred는 컴파일러가 아직 타입을 결정할 충분한 정보를 가지고 있지 않으며, 이 지연된 노드를 완전히 해결하기 위해 더 많은 정보(종종 다른 추론된 타입들)를 수집하며 컴파일을 계속해야 함을 의미합니다.import type { Db } from '@lib/kysely/db';import type { ExpressionBuilder, ExpressionWrapper } from 'kysely';export const existsValidThing = < const T extends keyof Db, EB extends ExpressionBuilder<Db, keyof Db>,>( thingIdRef: ExpressionWrapper<Db, T, string | null>,) => { return ({ eb, or, exists }: EB) => { return or([ eb(thingIdRef, 'is', null), exists( eb .selectFrom('thing as t') .select(eb.lit(1).as('exists')) .innerJoin('category', 'category', 't.category_id') .where('t.id', '=', thingIdRef), ), ]); };};existsValidThing 헬퍼 함수에서 반환되는 익명 람다 함수의 시작 부분입니다. 그렇다면 왜 TypeScript가 이 헬퍼 함수의 타입을 해결하는 것을 그토록 어려워했을까요?Db는 약 30개의 데이터베이스 테이블과 각 테이블당 수십 개의 필드 매핑으로 가득 찬 거대한 인터페이스입니다.kysely는 타입 추론과 거대한 유니온(예: 데이터베이스의 테이블들 또는 테이블의 필드들)에 걸친 분산에 크게 의존하는 방식으로 구축되었습니다. 한 GitHub 댓글 작성자는 일부 엣지 케이스에서 복잡도가 O(n^x) 수준이라고 넌지시 언급하기도 했습니다.EB, 제네릭에서 옴)에 대해 명시적인 타입 선언이 있었음에도 불구하고, TypeScript는 여전히 이 람다의 반환 타입을 추론해야 했습니다. 이 반환 타입 자체는 각각의 반환 타입을 결정하기 위해 추론이 필요한 복잡한 중첩 함수 호출의 연속이었습니다.kysely가 강력한 타이핑으로 가능하게 하는 일들은 상당히 마법 같습니다. 하지만 그러한 작업들을 재사용 가능한 헬퍼로 분리하려고 시도하면, 충분히 큰 데이터베이스 환경에서는 예상치 못한 타입 체크 병목 현상이 발생할 수 있습니다.prisma-zod-generator로 생성된 타입들node를 업그레이드하고 모든 환경의 버전을 통일syncpack을 추가하고 모노레포 린팅 규칙 설정지표 | 이전 | 이후 | 변화 | 변화율(%) |
|---|---|---|---|---|
Files | 14,628 | 10,445 | -4,183 | -28.6% |
Lines of Library | 85,573 | 87,322 | +1,749 | +2.0% |
Lines of Definitions | 1,563,401 | 1,458,375 | -105,026 | -6.7% |
Lines of TypeScript | 205,561 | 89,162 | -116,399 | -56.6% |
Lines of JavaScript | 0 | 0 | 0 | 0.0% |
Lines of JSON | 197,264 | 197,258 | -6 | -0.0% |
Lines of Other | 0 | 0 | 0 | 0.0% |
Identifiers | 2,591,445 | 1,983,548 | -607,897 | -23.5% |
Symbols | 12,162,183 | 6,238,779 | -5,923,404 | -48.7% |
Types | 4,605,085 | 2,303,043 | -2,302,042 | -50.0% |
Instantiations | 41,244,435 | 25,282,289 | -15,962,146 | -38.7% |
Memory used | 7,065,937K | 3,522,442K | -3,543,495K | -50.2% |
Assignability cache size | 7,530,942 | 989,151 | -6,541,791 | -86.9% |
Identity cache size | 36,263 | 41,336 | +5,073 | +14.0% |
Subtype cache size | 58,647 | 20,457 | -38,190 | -65.1% |
Strict subtype cache size | 111,640 | 147,930 | +36,290 | +32.5% |
Tracing time | 2.72s | 0.46s | -2.26s | -83.1% |
I/O Read time | 1.30s | 0.93s | -0.37s | -28.5% |
Parse time | 2.69s | 1.56s | -1.13s | -42.0% |
ResolveModule time | 1.00s | 0.66s | -0.34s | -34.0% |
ResolveTypeReference time | 0.03s | 0.02s | -0.01s | -33.3% |
ResolveLibrary time | 0.02s | 0.02s | 0.00s | 0.0% |
Program time | 6.59s | 4.11s | -2.48s | -37.6% |
Bind time | 1.88s | 0.97s | -0.91s | -48.4% |
Check time | 226.19s | 38.23s | -187.96s | -83.1% |
transformTime time | 1.10s | 0.24s | -0.86s | -78.2% |
commentTime time | 0.15s | 0.02s | -0.13s | -86.7% |
I/O Write time | 0.40s | 0.06s | -0.34s | -85.0% |
printTime time | 2.60s | 0.51s | -2.09s | -80.4% |
Emit time | 2.61s | 0.51s | -2.10s | -80.5% |
Dump types time | 132.73s | 33.63s | -99.10s | -74.7% |
Config file parsing time | 0.08s | 0.04s | -0.04s | -50.0% |
Up-to-date check time | 0.00s | 0.00s | 0.00s | 0.0% |
Build time | 374.32s | 78.55s | -295.77s | -79.0% |
아직 댓글이 없습니다.
첫 번째 댓글을 작성해보세요!

라이트 모드 인플레이션
Inkyu Oh • UI/UX

useEffectEvent의 즐거움
Inkyu Oh • Front-End

시그널(Signals) vs 쿼리 기반 컴파일러(Query-Based Compilers)
Inkyu Oh • SW Engineering

객체 배열(SoA 패턴)이 인터리브 배열을 이기는 이유: JavaScript 성능의 심연
Inkyu Oh • Front-End