Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for LiveReload without browser extensions #43697

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

vpavic
Copy link
Contributor

@vpavic vpavic commented Jan 6, 2025

This commit improves Dev Tools live reload capabilities by adding support for appending LiveReload.js script to rendered web pages.

See gh-32111

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 6, 2025
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
class LiveReloadServletConfiguration {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This configuration contains Servlet-specific bits needed to set up everything. If something like this is a viable approach, I assume WebFlux-specific equivalent is needed as well (I've never used Dev Tools with WebFlux so I'm unaware if there are any limitations).

private final String scriptSnippet;

public LiveReloadScriptFilter(int liveReloadPort) {
this.scriptSnippet = String.format("<script src=\"/livereload.js?port=%d\"></script>", liveReloadPort);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps something to consider is embedding the script in what LiveReload.js readme refers to as slightly smarter way, see https://github.com/livereload/livereload-js?tab=readme-ov-file#using-livereloadjs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This updates the existing livereload.js to latest version from https://github.com/livereload/livereload-js.

@@ -284,8 +284,6 @@ If you find such a problem, you need to request a fix with the original authors.
== LiveReload

The `spring-boot-devtools` module includes an embedded LiveReload server that can be used to trigger a browser refresh when a resource is changed.
LiveReload browser extensions are freely available for Chrome, Firefox and Safari.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether it's needed to explicitly call out here that browser extensions are no longer needed and Spring Boot provides everything needed.

@philwebb
Copy link
Member

philwebb commented Feb 4, 2025

Unfortunately I think the filter might generate invalid HTML. If I'm reading the code correctly then it inserts the <script> tag after </html>. That might work for now, but according to this stackoverflow.com post browsers might ban it in the future. We also have the issue of this not working outside of Spring MVC due to the use of a ResourceHandlerRegistration.

I guess the filter could parse the HTML and try to insert the script in the correct location. The problem there is that we might need to parse all responses just to tell if we're getting HTML. On top of that, the WebFlux side is also going to be pretty hard to address.

Flagging for team attention in case anyone else has any bright ideas.

@philwebb philwebb added for: team-attention An issue we'd like other members of the team to review status: on-hold We can't start working on this issue yet labels Feb 4, 2025
@vpavic
Copy link
Contributor Author

vpavic commented Feb 4, 2025

Unfortunately I think the filter might generate invalid HTML. If I'm reading the code correctly then it inserts the <script> tag after </html>.

That's true. I didn't (yet) put much effort into making the filter implementation robust as I wanted to pick up some feedback on the high-level approach first.

Looking into what some other web frameworks do this shouldn't be too hard - for example Hugo injects the <script> tag into <head> - see here. Apparently it used to inject it just before closing </body> tag but made the change in gohugoio/hugo#6821.

The problem there is that we might need to parse all responses just to tell if we're getting HTML.

The filter already takes response content type into consideration (requiring it to be text/html compatible) before doing anything with the response. If that condition is satisfied, only then we could parse the response.

@philwebb
Copy link
Member

philwebb commented Feb 5, 2025

The filter already takes response content type into consideration (requiring it to be text/html compatible) before doing anything with the response. If that condition is satisfied, only then we could parse the response.

I think it can't determine the content type until it's called the filter chain. That means we probably need to capture content for all requests in case they're HTML and need the script tag injected.

@vpavic
Copy link
Contributor Author

vpavic commented Feb 5, 2025

Yes, but that (wrapping) is different than parsing every response - that can still only be done if the response indeed is text/html compatible.

I've experimented with my PoC project a bit and got something (again very simple, not robust) working using ContentCachingResponseWrapper that places LiveReload script tag inside head tag.

I've also pushed those changes here.

This commit improves Dev Tools live reload capabilities by adding
support for appending LiveReload.js script to rendered web pages.

See spring-projectsgh-32111

Signed-off-by: Vedran Pavic <vedran@vedranpavic.com>
@vpavic
Copy link
Contributor Author

vpavic commented Feb 7, 2025

The filter should now work with any valid HTML and inserts LiveReload script element into head as the first child element even if the <head> tag itself is omitted. I was surprised to learn that omitting <head> is considered valid HTML per W3 validator as such input doesn't generate any warnings (see also relevant MDN docs).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: team-attention An issue we'd like other members of the team to review status: on-hold We can't start working on this issue yet status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants