Skip to content

Serve Vite-based Ember apps from development server - #653

Draft
tricknotes wants to merge 1 commit into
mainfrom
claude/vite-dev-server-hmr-y3xm8i
Draft

Serve Vite-based Ember apps from development server#653
tricknotes wants to merge 1 commit into
mainfrom
claude/vite-dev-server-hmr-y3xm8i

Conversation

@tricknotes

Copy link
Copy Markdown
Owner

Summary

Add support for serving Vite-based Ember applications (generated with ember-cli >= 6.8) from Vite's own development server in development mode, enabling hot module reloading without restarting Rails.

Key Changes

  • New DevServer class (lib/ember_cli/dev_server.rb): Manages the Vite development server lifecycle for a single Ember application

    • Boots the server lazily on first request
    • Detects if a server is already listening and reuses it
    • Provides HTTP methods (get, head, options_request) to fetch assets and HTML from the server
    • Handles timeouts and connection failures with helpful error messages
  • New DevServerProxy Rack middleware (lib/ember_cli/dev_server_proxy.rb): Proxies requests to the development server

    • Forwards GET, HEAD, and OPTIONS requests
    • Strips hop-by-hop headers to avoid connection issues
    • Rejects unsupported HTTP verbs with 405 responses
  • New Deploy::DevServer strategy (lib/ember_cli/deploy/dev_server.rb): Serves applications from the development server

    • Rewrites root-relative URLs in index.html to absolute URLs pointing at the development server
    • Enables Vite's HMR client to connect directly to the development server
  • Enhanced App class (lib/ember_cli/app.rb):

    • Adds dev_server? method to detect when an app should use the development server
    • Adds dev_server property to lazily initialize the DevServer
    • Selects Deploy::DevServer strategy by default for Vite-based apps in development
    • Supports dev_server configuration option to customize host, port, and timeout
  • Enhanced Shell class (lib/ember_cli/shell.rb):

    • Adds start_dev_server method to spawn the Vite development server in a separate process group
    • Adds dev_server_running? method to check server status
    • Properly signals and cleans up the development server process on exit
  • Enhanced Command class (lib/ember_cli/command.rb): Adds dev_server method to construct the Vite CLI command

  • Enhanced PathSet class (lib/ember_cli/path_set.rb): Adds vite property to locate the Vite executable

  • Comprehensive test coverage: Includes unit tests for all new classes and integration tests verifying the full request flow

Notable Implementation Details

  • The development server is started in its own process group, allowing Rails to cleanly shut down the entire server tree on exit
  • Root-relative URLs in index.html are rewritten to absolute URLs so the browser loads Vite's HMR client directly from the development server, not through Rails
  • Assets referenced relatively by the Ember application are still proxied through Rails, maintaining compatibility with the existing asset pipeline
  • The implementation gracefully falls back to reusing an existing server if one is already listening on the configured host and port, enabling manual npm start workflows
  • Configuration is optional; sensible defaults (127.0.0.1, available port, 30-second timeout) are provided

https://claude.ai/code/session_01RvmVfpMX8Dou7euMFAyzf4

Vite-based Ember applications (`ember-cli >= 6.8`) were built once,
synchronously, on the first request in `development`, so picking up a
change meant restarting Rails. The classic (Broccoli-based) build avoids
that with `ember build --watch` and `ember-cli-rails-addon`, neither of
which is available to the Vite-based build.

Serve those applications from Vite's own development server instead --
the one the blueprint's `npm start` script runs. `EmberCli::DevServer`
starts it on the first request, waits for it to accept connections, and
signals its process group when Rails exits. If something is already
listening on the configured address, it is used as-is, so a fixed `port`
lets several Rails workers, or a hand-started `npm start`, share one
server.

`EmberCli::Deploy::DevServer` reads `index.html` over HTTP and rewrites
its root-relative `src` and `href` attributes to absolute URLs on the
development server. Loading `@vite/client` from there is what makes the
Vite client open its HMR WebSocket against the development server
directly, so Rails never proxies the socket. Assets the application
references relatively are still requested from Rails, and
`EmberCli::DevServerProxy` forwards them to the development server so
they resolve the same way they do when served out of `dist`.

The strategy is chosen by default only for Vite-based applications in
`development`, and is configured -- or disabled -- with the `dev_server`
option. `test` and `production` continue to be served from the output of
`ember build`, and the classic build is untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvmVfpMX8Dou7euMFAyzf4
@tricknotes
tricknotes marked this pull request as draft August 31, 2026 12:21
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.

1 participant