명시 배선 — import한 것만 싣는다
browserDeps()는 프리셋이다 — 한 줄로 서는 대신, 프리셋이 참조하는 것은 옵션과 무관하게 전부 번들에 실린다. pointer: false를 줘도 크기가 같은 이유다(실측 53.90 vs 53.91 KB min): 번들러는 "실행되나"를 못 보고 "참조하나"만 본다. 옵션은 동작을 끄는 문이지 바이트를 빼는 문이 아니다.
바이트를 빼는 문은 이것이다 — createPlotDeps에 조각을 직접 넘긴다:
/**
* 명시 배선의 실물 — explicit-wiring.md가 이 파일을 그대로 임베드하고,
* `pnpm --filter charts-docs type-check`가 컴파일을 지킨다.
*
* 프리셋(browserDeps)과의 차이는 하나다: **여기서 import한 것만 번들에
* 실린다.** 포인터·구분자·그라디언트 페인터를 import하지 않았으므로
* 번들러가 실을 방법이 없다 — 런타임 플래그가 아니라 참조 부재가 문이다.
*/
import {
candleSeries,
createCanvasRenderer,
createCanvasTextMeasurer,
createPlotDeps,
frameScheduler,
} from "@finchart/core";
import {
createDomAxisLabels,
createDomLayers,
cssReader,
PlotBuilder,
} from "@finchart/dom";
const deps = (container: HTMLElement) =>
createPlotDeps({
createLayers: (width, height) => createDomLayers(container, width, height),
createRenderer: createCanvasRenderer,
createStyleReader: () => cssReader(container),
createTextMeasurer: createCanvasTextMeasurer,
createAxisLabels: createDomAxisLabels,
createScheduler: frameScheduler(),
// 상호작용이 필요해지면 그때 import한다 — 붙이는 순간부터 값을 낸다:
// interactions: pointerInteractions(container),
// pane을 나눠 쓰게 되면: createDividers: createDomDividers,
});
const plot = PlotBuilder.create(deps, candleSeries())
.addDataPoints([
{ x: 0, open: 100, high: 108, low: 98, close: 106 },
{ x: 1, open: 106, high: 112, low: 104, close: 109 },
{ x: 2, open: 109, high: 111, low: 101, close: 103 },
])
.setSize(800, 400)
.build(document.getElementById("chart")!);
export { plot };같은 캔들 차트가 45.1 KB min · 13.9 KB brotli로 선다 — 프리셋 (53.9 KB min · 15.9 KB brotli) 대비 −8.8 KB min (2026-08-16 실측, esbuild + brotli). 빠진 것은 정확히 import하지 않은 것들이다:
| 안 실린 것 | min | 필요해지면 |
|---|---|---|
| 포인터 어휘 전부 | 6,171 B | interactions: pointerInteractions(container) |
| pane 구분자 드래그 | 1,452 B | createDividers: createDomDividers |
| 그라디언트 페인터 | 931 B | createCanvasRenderer(surface, { painters: { [LINEAR_GRADIENT]: paintLinearGradient } }) |
| 프리셋 배선 자체 | ~600 B | — |
그라디언트는 페인터 없이도 깨지지 않는다 — area의 fillBottom이나 charts/linear-gradient 스타일은 첫 stop의 단색으로 강등된다(폴백 계약). 그라디언트가 보고 싶어지면 위의 painters 한 줄이 문이다.
그래도 남는 것 — 그리고 남는 이유
명시 배선까지 내려가도 두 개는 남는다. 크기가 작아서 봐주는 것이 아니라, 각각 계약이 근거다:
- M4 데시메이션 기본 (~1 KB) —
createPlotDeps의 기본 정책이다. 파생 시리즈(지표)가 붙는 순간 100k 점이 여기 기대 선다. 이것을 빼면 "지표를 붙였더니 느려졌다"가 기본 동작이 된다 — 성능 예산 (성능 가이드)이 이 기본값 위에 서 있다. 자기 정책이 있으면createDecimation으로 갈아 끼운다. - 축 드래그 소비자 (900 B) — plot의 입력 계약(X2)의 일부다. 입력 스택은 headless에서도 1급이라(
routeInput으로 합성 입력을 넣는다 — 차트를 테스트한다), 브라우저 배선이 아니라 plot 자신에 산다.
이 목록이 자라면 그것은 버그다 — 동승자는 문(import 단위) 또는 근거(계약 명문) 중 하나를 가져야 하고, "작아서 괜찮다"는 근거가 아니다 (PRINCIPLES 27).
언제 무엇을 쓰나
- 프리셋 — 시작할 때, 프로토타입, 상호작용 다 쓰는 트레이딩 화면. 60초가 서고, 그라디언트·구분자·핀치가 그냥 된다.
- 명시 배선 — 임베드 위젯, 정적 차트, 바이트가 예산인 곳. 필요한 조각을 필요해질 때 import한다 — 위 표가 가격표다.
둘은 같은 PlotDeps 계약의 두 조립법이라 언제든 갈아탈 수 있다 — 프리셋으로 시작해 명시 배선으로 내려가는 데 컴포넌트 코드는 안 바뀐다 (PlotBuilder.create(deps, …)의 deps만 간다).