Skip to content

Conversation

@EvanCarroll
Copy link

@EvanCarroll EvanCarroll commented Dec 22, 2025

Migrates the live reload WebSocket server from the standalone ws crate to native Axum WebSocket support:

  • Replace ws::WebSocket with axum's built-in WebSocket extractor
  • Use tokio::sync::broadcast for message broadcasting to clients
  • Integrate WebSocket endpoint into main Axum router at /livereload
  • Serve livereload.js via dedicated route instead of fallback handler
  • Remove separate WebSocket server thread (now runs on same port as HTTP)

Also fixes build error notification via WebSocket:

  • Send reload message on build errors so browser auto-refreshes
  • Handle 404 responses in error_injection_middleware for error display
  • Include livereload.js in error page so it can reload when fixed
  • Don't interfere with WebSocket upgrades (101) in middleware

Additional improvements:

  • Add WebSocket ping/pong keepalive (30s interval) for connection health
  • Add graceful shutdown support via with_graceful_shutdown()
  • Handle Message::Close and Message::Pong explicitly in WebSocket handler
  • Remove vestigial ws_port variable (WebSocket now on same port as HTTP)
  • Remove unnecessary #[derive(Clone)] from AppState (already Arc-wrapped)

Dependencies:

  • Add "ws" feature to axum for WebSocket support
  • Add "sync" feature to tokio for broadcast channels
  • Remove ws, tower, tower-http, tracing, tracing-subscriber crates

IMPORTANT: Please do not create a Pull Request adding a new feature without discussing it first.

The place to discuss new features is the forum: https://zola.discourse.group/
If you want to add a new feature, please open a thread there first in the feature requests section.

Sanity check:

  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?

Code changes

(Delete or ignore this section for documentation changes)

  • Are you doing the PR on the next branch?

If the change is a new feature or adding to/changing an existing one:

  • Have you created/updated the relevant documentation page(s)?

Migrates the live reload WebSocket server from the standalone `ws` crate
to native Axum WebSocket support:

- Replace ws::WebSocket with axum's built-in WebSocket extractor
- Use tokio::sync::broadcast for message broadcasting to clients
- Integrate WebSocket endpoint into main Axum router at /livereload
- Serve livereload.js via dedicated route instead of fallback handler
- Remove separate WebSocket server thread (now runs on same port as HTTP)

Also fixes build error notification via WebSocket:

- Send reload message on build errors so browser auto-refreshes
- Handle 404 responses in error_injection_middleware for error display
- Include livereload.js in error page so it can reload when fixed
- Don't interfere with WebSocket upgrades (101) in middleware

Additional improvements:

- Add WebSocket ping/pong keepalive (30s interval) for connection health
- Add graceful shutdown support via with_graceful_shutdown()
- Handle Message::Close and Message::Pong explicitly in WebSocket handler
- Remove unnecessary #[derive(Clone)] from AppState (already Arc-wrapped)

Cleanup of vestigial ws_port code:

- Remove ws_port parameter from create_new_site() function signature
- Simplify enable_live_reload_with_port() to use interface_port directly
- Update both call sites in serve() to remove the None argument
- Update test helper to remove ws_port parameter
- Fix test assertion to verify live_reload uses interface_port

Dependencies:

- Add "ws" feature to axum for WebSocket support
- Add "sync" feature to tokio for broadcast channels
- Remove ws, tower, tower-http, tracing, tracing-subscriber crates
@EvanCarroll
Copy link
Author

EvanCarroll commented Dec 22, 2025

A shorter commit message of the most relevant parts would just be.

  • Removes all the ws port stuff, and uses axum instead to upgrade the socket.
  • Handles build errors, and gives users feedback.
  • Solves issues with ping/pong and graceful shutdown.

This gets done what I needed to get done with Axum before I send over the commits for the pipeline changes I made back in October (sorry I cleaned up all that code though and I would like to get it in in smaller batches). One of things I needed was for livereload to be handled outside of the fallback.


When I say handles build errors, this now comes across the websocket, so if you break something in front-matter you'll see the error instantly on the website. Before you'd have to watch the zola serve output or refresh the page (which would only give you the error, after you fixed it you'd have to refresh again because livereload didn't work on error pages).

Screenshot_2025-12-22_01-18-10

@EvanCarroll
Copy link
Author

I have a lot of work I'd like to do Zola. I'd like to add tracing for the webserver (so you can see when a response is sent). And I still really want to work that pipeline stuff in because I got a few killer features I'd like to publish as modules (namely compression, and encryption). If there anything I can do to make the turnaround on this faster, please tell me. What I'm aiming for is no controversy and easy value.

(0 problem though, obviously this patch isn't 1 day old and I don't expect it to land in 24 hours).

@Keats
Copy link
Collaborator

Keats commented Dec 23, 2025

I have a lot of work I'd like to do Zola. I'd like to add tracing for the webserver (so you can see when a response is sent). And I still really want to work that pipeline stuff in because I got a few killer features I'd like to publish as modules (namely compression, and encryption). If there anything I can do to make the turnaround on this faster, please tell me. What I'm aiming for is no controversy and easy value.

There's another PR to add logging that should cover the first part.
As mentioned before, compression and encryption are not going to be added to Zola so I wouldn't spend time on that.

0.22 is mostly frozen right now in terms of feature, except small things like this PR or the logging one. The giallo change is a big one and I don't want to do a big release along with it.
I have some big internal arch changes in mind for 0.23 which will use Tera 2 but I don't know whether it will make sense or not until i try it so I wouldn't do any big changes soon if I were you.

@EvanCarroll
Copy link
Author

I have a lot of work I'd like to do Zola. I'd like to add tracing for the webserver (so you can see when a response is sent). And I still really want to work that pipeline stuff in because I got a few killer features I'd like to publish as modules (namely compression, and encryption). If there anything I can do to make the turnaround on this faster, please tell me. What I'm aiming for is no controversy and easy value.

There's another PR to add logging that should cover the first part. As mentioned before, compression and encryption are not going to be added to Zola so I wouldn't spend time on that.

The patch provided doesn't use tracing. If you want tracing I could write you a better one. It was in my original PR too. Tracing would unify the logging and verbosity settings in zola serve with the rest of the information you would want.

You don't have to accept the compression and encryption patches (though I would -- why leave a killer feature like encryption behind), but even if not let's create a mdoular infrastructure that allows us to do things like html-templates/encryption/compression/Typst?

Btw, the whole graceful shutdown is gone. we can add it back later if people want it.

@EvanCarroll EvanCarroll requested a review from Keats December 27, 2025 00:29
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