perf(dev): use SSR bundling instead of subprocess for hot reload#72
Merged
Conversation
Replaces the subprocess-per-request architecture with esbuild-based SSR bundling to bypass Deno's module cache. This eliminates: - Subprocess spawn overhead (50-200ms per request) - Shiki highlighter reinitialization (200-500ms first render) - Redundant page scanning (subprocess rescanned on each request) The new approach: 1. Generates SSR entry code that imports page + layout components 2. Bundles with esbuild (reads fresh files from disk) 3. Writes to unique temp file (bypasses Deno's import cache) 4. Imports and executes to get fresh components 5. Renders in parent process (keeps Shiki warm) Measured improvement: 600-1200ms -> 150-330ms per page render. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous code called both stopSSRBundler() and stopEsbuild() in parallel, but both called esbuild.stop() on the same global instance. This caused race conditions in subprocess cleanup, leading to leaked child processes detected by Deno's test runner. Now we only call stopEsbuild() once, and removed the redundant stopSSRBundler export. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Switch from esbuild.build() to esbuild.context() + ctx.dispose() for SSR bundling. This gives explicit lifecycle control over the esbuild child process, ensuring it's properly cleaned up after each build. The previous approach relied on esbuild's global service and stop(), which had race conditions in subprocess cleanup that caused test failures in CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The esbuild.stop() function returns before the child process fully terminates, causing subprocess leak detection failures in CI tests. Adding a small delay ensures the process has fully terminated before test cleanup runs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
How it works
Performance
Before: 600-1200ms per page render
After: 150-330ms per page render
~50-75% reduction in dev server response time.
Test plan
🤖 Generated with Claude Code