Skip to content

Feat(playground): Add Native Sandbox Engine#291

Open
jlukic wants to merge 10 commits into
mainfrom
playground-engine
Open

Feat(playground): Add Native Sandbox Engine#291
jlukic wants to merge 10 commits into
mainfrom
playground-engine

Conversation

@jlukic

@jlukic jlukic commented Jul 3, 2026

Copy link
Copy Markdown
Member

The docs playground now runs on @semantic-ui/playground, a new package that owns what playground-elements did: builds, module resolution, sandbox serving, and the code editor. Upstream is frozen and its architecture fought us. Per-instance compile workers raced dev-server transforms (the one-winner bug), the service worker had documented wait-forever corners, and editor capabilities meant reaching into internals. The engine is built around the opposite choices: one shared tooling worker per page, fully materialized sessions with broadcast recovery, and an editor adapter whose extension points are the API.

The engine is headless. Files in, live preview URL and diagnostics out, so the same contract serves the docs UI, the REPL share links, and eventually agents rendering components for iteration.

Changes

  • New packages/playground: PlaygroundProject, shared tooling worker, sandbox service worker, CodeMirror editor adapter
  • TypeScript completions, hover, and diagnostics on in js/ts files, composing with the SUI LSP in html files (was no-completions)
  • Render-only previews never load TypeScript. JS builds use an es-module-lexer fast path and the 3.5MB TS chunk loads lazily
  • Pragma markers get an owned contract: sui-hide / sui-fold canonical, playground-* as aliases. Display-only, marker comments never visible, expanding a fold no longer mutates the document
  • ExamplePreview and CodePlayground rebuilt on the engine. Previews recover by iframe replacement and reload on theme change
  • playground-elements uninstalled: 55 packages gone from docs including the deprecated MWC and Comlink chains, along with the vendored sandbox files, dev worker shim, upstream patch, and CM5-era libs
  • Share-link codec moved into the package on native CompressionStream, byte-compatible with existing links both directions

Risk

6/10 — every example page, homepage preview, and the REPL sit on this path, though nothing in the published framework runtime changes. Failure modes worth a skeptical look:

  • Pragma whitespace-extension heuristics were tuned against the injection shapes in the corpus. Unusual marker layouts could show stray blank lines or swallow one
  • The service worker self-heals on update/termination (retry-once sends, broadcast recovery), verified single-tab. Multi-tab with a mid-update worker is lightly exercised
  • Completion feel differs from upstream (no 1250ms refinement window or fuzzy-match scoring). Correctness is covered, ergonomics may want tuning
  • Inline example natural-sizing mirrors the old measurement constants but wasn't pixel-audited across all docs pages
  • A $el.tooltip is not a function console error appears in dev from Sidebar's collapsed-tooltip script. Production is clean. Believed pre-existing (Sidebar code untouched) but not verified against a main dev server

How to Test

  • /examples/todo-list — folds (click the ), tab switching, edit code and watch the preview rebuild
  • /examples/tailwind — wasm compilation in the sandbox, Use Panels layout
  • /examples/signals — hidden <head> block (line numbers jump), console output panel
  • /examples/cdn-authoring — literal hide markers in example source, live CDN inside the sandbox
  • /docs/api/reactivity/array-helpers — 8 inline playgrounds on one page (the old race's worst case)
  • /playground — open any example's View in Playground link, or paste an old share link
  • Completions: { in an html file (SUI LSP), any local symbol prefix in a js file (TypeScript)
  • After editing worker or service-worker source: npm run build in packages/playground, then node docs/scripts/sync-sandbox.mjs

jlukic added 8 commits July 3, 2026 13:06
One shared tooling worker per page multiplexing all sessions (build,
bare-import CDN rewriting, lazy TypeScript), a materialized-session
service worker with broadcast recovery, and a headless PlaygroundProject
that turns a file set into a live preview URL. Sandbox assets build
self-contained so they never enter a dev server's transform pipeline.
example-preview keeps its tag and consumer contract but now owns a
PlaygroundProject instead of wrapping playground-elements. Accepts a
shared project setting so editor surfaces can drive the same preview.
Files travel as data, so the sample/html closing-tag escaping dance is
gone. Frames recover by node replacement, never reload.
Editor surface speaks filenames, strings, and plain-data markers so a
future Monaco binding stays a binding. Per-file editor states preserve
undo history across tab switches. Pragma regions (sui-hide/sui-fold,
playground-* aliases) are display-only decorations — expanding a fold
never shows the marker comment and never mutates the document.
CodePlayground now drives a shared PlaygroundProject: TS completions,
hover, and diagnostics compose with SUI LSP per file type, replacing
the no-completions workaround.
Vendored sandbox files, the dev worker shim, the CM5-era lib files, and
the upstream patch all go — the sandbox engine owns these concerns.
Uninstalling drops 55 packages from docs, including the deprecated MWC
and Comlink chains.
The dynamic-import case caught a real bug — es-module-lexer spans
include the quotes for dynamic imports, so rewrites dropped them.
@github-actions github-actions Bot added Tests Modifies tests Docs Modifies documentation labels Jul 3, 2026
@semantic-bundle-bot

semantic-bundle-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

⚪ Bundle size: no meaningful change · +1513 shipped LOC for a138a7f

Base: main · Run: #28677553024 · Raw: size-report.json

Feat(playground): Add Native Sandbox Engine

Note

No shipped bundle changed size.

0 larger · 0 smaller · 24 unchanged · +1513 shipped LOC · +175 comment LOC

signal result
component brotli 0 B
Shipped LOC +1513
Comment LOC +175
Changed bundles 0 / 24

No bundle changed size. 🎉

LOC by scope: +1513 shipped LOC · +175 comment LOC

Shipped LOC excludes comments and blank lines.

scope shipped LOC comment LOC
playground +1513 +175
All 24 bundles, gzip, and raw sizes
bundle group brotli Δ brotli gzip Δ gzip raw Δ raw
compiler package 6.1 KB 6.8 KB 18.4 KB
component 🎯 package 48.8 KB 55.9 KB 170.9 KB
query package 16.0 KB 17.8 KB 52.5 KB
reactivity package 7.1 KB 7.8 KB 22.2 KB
renderer package 43.2 KB 49.2 KB 150.9 KB
specs package 53.9 KB 63.8 KB 236.3 KB
tailwind package 67.3 KB 85.3 KB 335.3 KB
templating package 28.8 KB 32.3 KB 95.9 KB
utils package 17.6 KB 19.7 KB 50.9 KB
framework framework 130.1 KB 166.0 KB 698.5 KB
button primitive 12.0 KB 15.2 KB 128.6 KB
card primitive 3.0 KB 3.5 KB 15.8 KB
container primitive 694 B 888 B 2.4 KB
divider primitive 1.6 KB 1.9 KB 6.5 KB
icon primitive 26.3 KB 35.0 KB 143.7 KB
image primitive 776 B 993 B 2.2 KB
input primitive 3.9 KB 4.5 KB 15.6 KB
label primitive 1.3 KB 1.6 KB 5.5 KB
menu primitive 14.2 KB 16.3 KB 64.5 KB
modal primitive 1.7 KB 2.0 KB 6.7 KB
rail primitive 534 B 695 B 1.5 KB
segment primitive 3.1 KB 3.7 KB 19.7 KB
spinner primitive 1.8 KB 2.1 KB 8.0 KB
table primitive 555 B 692 B 1.3 KB

brotli q11 · gzip l9 · vs main · fresh build both sides · 58s

Correctness: nested pragma regions no longer crash the editor (sorted,
outermost-wins decorations), orphaned markers hide, expanded folds are
keyed by mapped positions, a fragment containing <header> is not a
document, whole-project resets outrank per-file language-service pins,
stale builds can't emit buildDone or resurrect old files through the
send retry, ack listeners clean up on timeout, recovery failures
surface, re-opening the current file applies external content, and the
tooling worker URL follows the sandbox scope.

The language service now ships a concatenated lib.d.ts (es2022 + dom),
so globals resolve in completions and diagnostics instead of producing
phantom errors.

Docs: build errors render in the preview instead of an eternal spinner,
missing-session recovery is throttled, share links route through the
engine codec (fflate dropped), and the playground-elements-era
scriptTypes, dead CSS selectors, stale plan instructions, and an
orphaned 8.9MB vendored TypeScript copy are gone. The package builds
with the root build:packages pipeline.
Also adds a guestbook entry for the session.
@jlukic jlukic added the Preview Create preview server for a PR label Jul 3, 2026
@semantic-deploy-bot

semantic-deploy-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

🟢 Preview Ready for a138a7f

project status preview logs
docs 🟢 Ready Preview logs
mcp ⚪ NA

Run: #28677562656 · docs semantic-next-hh1gg7psf-semantic-ui.vercel.app

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Docs Modifies documentation Preview Create preview server for a PR Tests Modifies tests Tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant