Repository navigation
Compare page renders in each tab's websocket process - #54
Merged
Merged
Conversation
A page found out what changed by requesting itself again and diffing the answer against its live DOM, which scripts have modified since. So a change to an owned element's attributes, such as an island's props, could only be handled by reloading. Each open page already has a websocket process that lives as long as the page. With the new :document option, a function that renders a page's HTML, and :morph, that process keeps the HTML the server last rendered for its page. On a document update it renders the page again and compares the two server renders, then sends the page only what applies to it: nothing, a reload, or the new HTML with the owned elements whose attributes the server changed. For those elements the client sets the attributes and dispatches a cancelable volt:element-update event; the page reloads only if nothing handles it. Pages that were served other HTML than the server can reproduce fall back to revalidating themselves.
The comparison of two server renders now also names the attributes the server changed on <html> and <body>, and the metadata and links it changed in <head>. The client applies only those, so an attribute a script set, such as a theme, stays; a blind copy from the new document would remove it. A page's websocket process rendered the page when it connected, to have something to compare with. The dev server now keeps the HTML of each page it serves until the page connects, so opening a page costs no extra render. At most 64 pages per session are kept, for pages that never connect. A browser test covers the whole push flow: no request from the page, an owned element re-rendered by its owner, and root and head changes applied.
This was referenced Oct 3, 2026
Merged
Merged
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.
Builds on the page revalidation and opt-in
morphfrom 0.20.0. A page found out what changed by requesting itself again and diffing the answer against its live DOM, which scripts have modified since. That left three gaps: attributes on<html>/<body>, metadata in<head>, and elements owned by client code (an island's props), which could only be handled by reloading.Idea
Each open page already has a websocket process that lives as long as the page. With a new
:documentoption and:morph, that process keeps the HTML the server last rendered for its page. On a document update it renders the page again and compares the two server renders, then sends the page only what applies to it:The function is called with the page's path, followed by the listed arguments, and returns
{:ok, html}or:error.What the comparison enables
<html>and<body>are applied. One a script set, such as a theme, is in neither render and stays.volt:element-updateevent. Its owner re-renders and callspreventDefault(); the page reloads only if nothing handles it.The page starts from the HTML it was served: the dev server keeps it until the page connects, so opening a page costs no extra render. At most 64 pages per session are kept, for pages that never connect. A page that was served other HTML than the server can reproduce falls back to revalidating itself, as in 0.20.0.
Verification
mix test: 770 passed.mix lintpasses.--include integration, not run in CI): 33 passed, including an end-to-end test of the push flow: no request from the page, an owned element re-rendered by its owner, root and head changes applied, a script-set attribute kept.Open points
:documentandvolt:element-updateare new public API between Volt and frameworks.