Skip to content

feat: reduce binary size by making D2 support opt-in via build tag #12

@engineervix

Description

@engineervix

Problem

The released binary is ~30 MB (stripped). This is large for a CLI documentation tool.

Root Cause

The binary is already built with -ldflags="-s -w" (debug symbols stripped), so there are no easy wins there. The size comes almost entirely from the D2 diagram library and its transitive dependencies:

Package Role Symbols
github.com/dop251/goja Full ECMAScript 5.1 JS VM — bundled by D2 6,597
oss.terrastruct.com/d2 Diagram compiler + SVG renderer 1,689
golang.org/x/image Image codecs (PNG/JPEG/GIF) — pulled by D2
github.com/golang/freetype Font rendering for D2 text measurement
github.com/google/pprof Profiling — pulled by D2

Everything else (cobra, goldmark, chroma, fsnotify, toml) is cheap. Without D2, the binary would be roughly 8–12 MB.

Proposed Fix: Build Tag

Add //go:build d2 to internal/parser/d2.go and a no-op stub for default builds:

// internal/parser/d2_stub.go — compiled by default
//go:build !d2

package parser

import "github.com/yuin/goldmark"

func NewD2Extension() goldmark.Extender { return noopExtension{} }
// internal/parser/d2.go — only compiled with -tags d2
//go:build d2

package parser
// ... existing implementation unchanged

The D2 import in go.mod would become conditional (or stay as-is since unused imports are dead-code eliminated by the linker when the build tag excludes the file).

Default install (~10 MB):

go install github.com/engineervix/kwelea@latest

With D2 diagram support (~30 MB):

go install -tags d2 github.com/engineervix/kwelea@latest

D2 fenced blocks (```d2) in the default build would fall back to rendering as syntax-highlighted plain text.

Other Options Considered

Option Savings Notes
Build tag (recommended) ~20 MB Keeps feature, opt-in
Shell out to d2 CLI ~20 MB Requires separate d2 install
Drop D2 entirely ~20 MB Cleanest; d2 blocks become code
UPX compression ~40–50% Adds startup latency; not portable

Acceptance Criteria

  • Default go install produces a binary ≤ 12 MB
  • go install -tags d2 produces a full-featured binary (D2 diagrams work)
  • just build uses the default (no D2) build
  • just build-d2 (new recipe) builds with D2 support
  • README documents both install variants
  • d2 fenced blocks in default build render gracefully as code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestperformancePerformance improvements

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions