Skip to content

perf(cli): Load syntax highlighting lazily and allow compiling it out - #1765

Merged
BYK merged 1 commit into
mainfrom
perf/cli-lazy-syntax-highlight
Oct 31, 2026
Merged

BYK merged 1 commit into
mainfrom
perf/cli-lazy-syntax-highlight

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Groundwork for #1731. The plan there is to build @sentry/mcp-server from the real CLI runner with a smaller route map. That build doesn't fit the size budget today, and about 1.2 MB of the overage is syntax highlighting. buildCommand → formatters/output → human → markdown imports cli-highlight at the top level, which brings in all of highlight.js and parse5. So every command loads it, even if it never renders a fenced code block.

formatters/highlight.ts is now the only module that imports cli-highlight, and it does two things:

  • Lazy at runtime. It loads cli-highlight on the first code block, using the same _require + REQUIRE_ALIAS_FILTER pattern as formatters/json. The npm bundle and the SEA bundle still include the code, but it only runs when needed. Rendered output doesn't change.
  • Can be compiled out. A bundle that doesn't need colored code blocks sets define: { __SENTRY_CLI_SYNTAX_HIGHLIGHT__: "false" }. esbuild folds the guard, drops the dead require(), and leaves out highlight.js, parse5, and cli-highlight's copy of chalk. Code blocks then use the existing fallback color, uniform yellow, the same as an unknown language. I chose a define over aliasing the module because it's one line in any esbuild config, needs no resolver plugin, and follows the guard pattern already used for SENTRY_CLI_VERSION and __SENTRY_DEBUG_ID__.

Sizes from esbuild metafiles, using script/bundle.ts options:

entry default __SENTRY_CLI_SYNTAX_HIGHLIGHT__=false
src/index.ts (full CLI) 7,869,910 B 6,632,859 B (−1,237,051 B)
lib/command.ts graph 5,629,790 B 4,392,948 B
formatters/markdown.ts graph 1,303,407 B 71,864 B

The default bundle grows by 186 B compared with main. On the npm bundle in a sandbox (50 interleaved runs, medians), startup dropped from 658 to 614 ms for sentry --version, from 718 to 664 ms for sentry help, and from 701 to 643 ms for sentry org list --help.

I also checked the rest of the formatter layer for eager heavy imports. None of them is a cheap win, so this PR leaves them alone:

  • human.ts → api-client.ts brings in @sentry/api (~400 KB). The MCP server needs it anyway.
  • sixel-dashboard.ts → sixel-image.ts brings in pngjs and jpeg-js (~52 KB). help.ts → sixel.ts also reaches them.
  • marked is ~39 KB, and the renderer needs it.

Plain output still runs the highlighter and then strips ANSI. It can't skip highlighting yet, because the stripped output doesn't always match the input byte for byte. That could be a follow-up.

via BYK.

--

View Session in Sentry

`markdown.ts` imported `cli-highlight` at the top level, so every command
that reaches `buildCommand` initialized all of highlight.js and parse5
(~1.2 MB of the npm bundle), even when it never renders a code block.

Move highlighting into `formatters/highlight.ts`, the only importer of
`cli-highlight`. It requires the package on the first code block through
the existing `_require` + `REQUIRE_ALIAS_FILTER` pattern, so the CLI
bundle keeps it but only runs it when needed. Bundles that don't need
colored code blocks, like the MCP server, can set
`__SENTRY_CLI_SYNTAX_HIGHLIGHT__` to `false`; esbuild then drops the
whole stack. Code blocks fall back to the existing uniform yellow.

Co-Authored-By: BYK <burak.kaya@sentry.io>
@vercel

vercel Bot commented Oct 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
sentry-local Skipped Skipped Oct 30, 2026 11:38pm UTC

Request Review

@BYK
BYK merged commit 3d507ad into main Oct 31, 2026
26 of 27 checks passed
@BYK
BYK deleted the perf/cli-lazy-syntax-highlight branch October 31, 2026 14:11
sentry-junior Bot added a commit that referenced this pull request Oct 31, 2026
Brings in the squash-merged #1763 (Zod English locale), #1764 (lazy server
stack) and #1765 (lazy syntax highlighting), which this branch had merged
from their PR branches.

Conflicts:
- packages/mcp-server/src/index.ts: kept deleted. #1764's lazy loading is
  already applied to the unified entry (commands/mcp.ts -> lib/mcp.ts ->
  lib/mcp/server.ts).
- script/bundle.ts, script/build.ts: kept the zod/v3 stub plugin. bundle.ts
  keeps the shared script/lib/require-alias-plugin.ts (the
  @sentry/mcp-server bundle uses it too) instead of main's inline copy.
  main's filter also lists list-command.ts, but on this branch that file no
  longer uses _require (the route registry replaced it), so it stays out.
- formatters/highlight.ts, syntax-highlight-bundle.test.ts: identical to
  main apart from comments that point at the shared require-alias plugin.
sentry-junior Bot added a commit that referenced this pull request Oct 31, 2026
Brings in the #1766 squash (route registry). This branch already merged
#1766's branch, and its final head only added main's #1763-#1765, which
are here too, so every conflict (`app.ts`, `lib/help.ts`,
`script/bundle.ts`) resolves to this branch's version: the application
setup and `setRoutes()` live in `lib/application.ts`, help names come from
`lib/app-identity.ts`, and the require-alias filter is the shared
`script/lib/require-alias-plugin.ts`. The tree is unchanged.

This branch was previously deployed

1 inactive deployment
Preview — d7835338 Deployed Oct 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant