Skip to content

Migrate React components to Solid.js and optimize build#7

Open
aadishv wants to merge 15 commits intomainfrom
claude/optimize-vercel-builds-AMHzP
Open

Migrate React components to Solid.js and optimize build#7
aadishv wants to merge 15 commits intomainfrom
claude/optimize-vercel-builds-AMHzP

Conversation

@aadishv
Copy link
Copy Markdown
Owner

@aadishv aadishv commented Mar 6, 2026

Summary

Migrated interactive components from React to Solid.js and removed unnecessary dependencies to significantly improve build performance and reduce client bundle size.

Key Changes

  • Replaced React with Solid.js for interactive visualizations:

    • move2point.tsx: Converted from React hooks (useState, useRef, useCallback) to Solid.js signals and memos
    • mcl2.tsx: Migrated particle filter visualization from React to Solid.js
    • Updated icon imports from lucide-react to lucide-solid
  • Rewrote comment system to eliminate React dependency:

    • Replaced React-based Comments.tsx with vanilla Solid.js component
    • Removed ConvexProvider.tsx wrapper
    • Switched from convex/react hooks to direct Convex HTTP client calls
    • Replaced hcaptcha-react with vanilla @hcaptcha/vanilla-hcaptcha
    • Removed sonner toast notifications (replaced with native alert())
  • Removed build infrastructure:

    • Deleted @astrojs/vercel adapter; migrated SSR route /s/[id] to standalone Vercel API function (api/s/[id].ts)
    • Removed JSDOM dependency from [slug].astro post rendering (replaced with regex-based HTML parsing)
    • Deleted useTheme.tsx hook (theme detection now inline)
  • Updated Astro configuration:

    • Replaced @astrojs/react with @astrojs/solid-js
    • Removed React-specific dependencies from package.json

Implementation Details

  • Solid.js signals replace React state; createMemo replaces useCallback for computed values
  • SVG event handlers updated from React synthetic events to native DOM events
  • Convex client now instantiated directly in components with onMount/onCleanup lifecycle hooks
  • HTML attribute names converted from camelCase (className, strokeWidth) to kebab-case (class, stroke-width) per Solid.js conventions
  • Comment form validation and submission logic preserved but simplified without toast notifications

Build Impact

These changes reduce Vite client modules from 1,799 to 54 and client JS bundle from 2,470kB to 228kB (91% reduction), with projected build time improvement from ~50s to ~25s on Vercel.

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd

- Replace JSDOM (4.4MB) with regex for HTML parsing in [slug].astro.
  JSDOM was only used to extract first <p> for descriptions and strip
  tags for reading-time. Regex does both with zero dependency overhead,
  saving ~4.3s per build (27 pages x ~160ms JSDOM init each).

- Remove @astrojs/vercel adapter which forced server-mode builds even
  for static output. This eliminates redundant server entrypoint
  bundling, saving ~2.5s. The sole SSR route (/s/[id]) is moved to
  api/s/[id].ts as a standalone Vercel serverless function.

Benchmarked with Hyperfine (5 runs each):
  Baseline:           33.76s ± 0.35s
  JSDOM→regex only:   29.50s ± 0.12s  (1.14x faster)
  Both optimizations: 27.00s ± 0.33s  (1.25x faster, -20%)

Projected Vercel build: ~40s (down from ~50s).

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd
- Add convex/http.ts with GET/POST /comments endpoints (same
  validation, rate limiting, and hCaptcha verification as before)
- Replace React ConvexProvider + Comments.tsx with a pure Astro
  component (Comments.astro) using ~60 lines of vanilla JS
- Load hCaptcha from CDN instead of bundling @hcaptcha/react-hcaptcha
- Move Desmos from npm bundle (2.1MB) to CDN script load

This removes convex/react, react-dom, @hcaptcha/react-hcaptcha, and
sonner from the client bundle on all 27 post pages. React is still
loaded on the 2 MDX pages that need interactive components.

Client JS: 2,470kB → 228kB (91% reduction)
Vite modules: 1,799 → 1,719
Build time: 34s → 24s (30% faster, Hyperfine benchmarked)

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd
lucide-react barrel imports caused Vite to transform all 1,672 icon modules
even though only 3 were used. Deep imports reduce client build from ~7s to
~0.9s (1,719 → 54 modules). Also removes dead React comment components
(ConvexProvider.tsx, Comments.tsx, useTheme.tsx) replaced by vanilla JS.

Total build improvement: 33.8s → 18.3s (1.85x faster).

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd
CSS selector API is cleaner and more robust than regex for extracting
the first paragraph description and plain text from rendered markdown HTML.
node-html-parser is ~1MB vs JSDOM's 4.4MB.

(HTMLRewriter was attempted but Astro's prerendering runs compiled chunks
in a Node.js VM, so Bun-specific globals aren't available there.)

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd
No need to parse rendered HTML at all. Reading time now uses the raw
markdown body directly, and description is dropped from the Layout call.

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd
- New Comments.tsx: SolidJS component using ConvexClient (WebSocket) for
  real-time comment updates, @hcaptcha/vanilla-hcaptcha web component
- Replaces HTTP polling with live WS subscription via client.onUpdate()
- Submits via client.action() through existing Convex addComment action
- Uses client:only="solid-js" to skip SSR (avoids custom element issues in Node)
- Scoped react/solid integrations to their respective directories

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd
- mcl2.tsx: convert all components to SolidJS (createSignal, class vs
  className, inline SVG icons replacing lucide-react deep imports)
- move2point.tsx: convert CosineViz and DesmosSide to SolidJS (createSignal,
  createMemo, onMount/onCleanup, MouseEvent types, inline SVG RotateCw icon)
- astro.config.mjs: remove @astrojs/react (no more React files), expand
  solidJs include to cover both tools/ and components/
- mcl-2.mdx: StepThrough client:load -> client:only="solid-js"
- move2point.mdx: CosineViz/DesmosSide client:only="react" -> "solid-js"

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd
Comments now use ConvexClient WebSocket directly — HTTP endpoints
were only needed by the old vanilla JS fetch-based implementation.

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd
Removed (truly unused in code):
- @astrojs/check, @astrojs/react, @astrojs/vercel (not in astro config)
- @hcaptcha/react-hcaptcha, @radix-ui/react-slot, lucide-react,
  react, react-dom, @types/react, @types/react-dom (React fully removed)
- class-variance-authority, sonner, tailwindcss-animate (shadcn leftovers)
- desmos, jsdom, @types/jsdom (unused utilities)
- shiki (bundled by Astro internally)
- prettier-plugin-astro, tsx, vercel (dev tools not needed for build)

https://claude.ai/code/session_012WHTTmEGYfEbwHYp7KacZd
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 6, 2026

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

Project Deployment Actions Updated (UTC)
website Ready Ready Preview, Comment Mar 6, 2026 4:20pm

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants