Skip to content

Remove CodeMirror dependency from live editor playground #25386

@Mossaka

Description

@Mossaka

Summary

The live editor playground (docs/public/editor/) currently loads 7 CodeMirror packages from the esm.sh CDN at runtime. This proposal replaces CodeMirror with vanilla JS to make the editor entirely dependency-free (zero external JS imports).

Current State

Three files in docs/public/editor/ use CodeMirror:

File Lines CodeMirror usage
editor.js 372 7 CDN imports, 2 EditorView instances (input + read-only output), theme compartments
hover-tooltips.js 290 1 CDN import (hoverTooltip), exports a CodeMirror extension. ~230 lines are pure DOM/logic
index.html 293 ~55 lines of .cm-* CSS rules

CodeMirror packages loaded from esm.sh:

  • codemirror@6.0.2 (EditorView, basicSetup)
  • @codemirror/state@6.5.4 (EditorState, Compartment)
  • @codemirror/view@6.39.14 (keymap, hoverTooltip)
  • @codemirror/lang-yaml@6.1.2
  • @codemirror/lang-markdown@6.5.0
  • @codemirror/language@6.12.1 (indentUnit)
  • @codemirror/theme-one-dark@6.1.3

These are not npm dependencies — they are runtime CDN imports in the JS files. The Astro docs site itself does not use CodeMirror (it uses Shiki via Starlight for static code highlighting).

Approach

Input editor → <textarea>

Replace the CodeMirror EditorView with a plain <textarea>:

  • Native undo/redo, text selection, copy/paste, scrolling
  • Add keydown listener: Tab inserts 2 spaces, Mod-Enter triggers compile
  • Add input listener: save to localStorage + schedule auto-compile
  • Content access: textarea.value instead of editorView.state.doc.toString()

Output display → <pre><code>

Replace the read-only CodeMirror EditorView with a <pre><code> element:

  • Content set via outputCode.textContent = result.yaml
  • Scrolling via overflow: auto

Hover tooltips → line-based mouse position calculation

The current tooltip system uses CodeMirror's character-level position awareness. Replace with monospace font math:

  1. Measure character width via a hidden <span> with the same monospace font
  2. On mousemove over textarea, calculate:
    • lineIndex = Math.floor((offsetY + scrollTop) / lineHeight)
    • charIndex = Math.floor((offsetX - paddingLeft) / charWidth)
  3. Extract the line from textarea.value.split('\n')[lineIndex]
  4. Reuse existing pure-logic functions (extractKeyFromLine, resolveKeyPath, lookupSchema, buildTooltipDOM) — these have no CodeMirror dependency
  5. Position a tooltip div absolutely near the mouse

Cache the line splits and invalidate on content change to avoid performance issues.

Theme switching → CSS only

Primer CSS already handles dark/light via data-color-mode="auto" on <html>. All Primer CSS variables (--bgColor-default, --fgColor-default) switch automatically. The entire CodeMirror Compartment-based theme machinery (oneDark toggle, applyCmTheme(), media query listener) is deleted with no replacement needed.

Tradeoffs

Lost Gained
Syntax highlighting (markdown input, YAML output) Zero external JS dependencies
Line numbers in gutter Instant load (no CDN fetch/resolution)
Bracket matching, code folding, search panel ~0 KB JS overhead (was ~200+ KB from CDN)
Pixel-perfect hover detection (now char-width approximation) No CDN availability risk (esm.sh outage-proof)
Simpler codebase (~150-200 lines JS vs ~660+)

Files Modified

  • docs/public/editor/index.html — swap mount divs for textarea/pre, update CSS
  • docs/public/editor/editor.js — remove CodeMirror, wire textarea events
  • docs/public/editor/hover-tooltips.js — adapt to textarea-based hover detection

No changes to:

  • docs/public/wasm/* (compiler integration unchanged)
  • docs/public/editor/autocomplete-data.json (schema data reused as-is)
  • Astro docs site or any other docs/ files

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions