Skip to content

Showcasing the integration of the different hotwire.dev parts into a typical Spring Boot Webapp

License

Notifications You must be signed in to change notification settings

innoq/hotwire-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hotwire DEMO

A simple Spring Boot Application to showcase the integration of Hotwire into a 'normal' Spring Boot Webapplication

Getting started

  1. Build the JS Parts
cd src/main/js
npm install
npm run build && npm run deploy
  1. Run the application
./mvnw clean install spring-boot:run

Point your browser to http://localhost:8080

under the hood

JS

The little JS Code that is necessary is built in src/main/js using snowpack, to add minimal overhead. The necessary call is wired to the build target of npm.

Since we needed two Button Handlers for the Turbo Streams examples, this also includes a short Stimulus Usage to hook up Controllers to those Buttons. Have a peek into ConnectSSEController.js and ConnectWebsocketController.js if you're interested.

The deploy target copies the JS Files (and their dependencies) to the static path of the Spring Boot Application from where they are served (Note: since we do this, the path is added to .gitignore to make sure we don't check in any stale JS - so all scripts wuold have to be added this way unless you write directly into the page)

In order for the demo to run properly you need to run npm run build && npm run deploy at least once, so the necessary files are created.

Java

The Spring app is mostly plain vanilla Spring Boot/WebMVC with Thymeleaf for rendering templates.

Spring Config

There are a few Configuration Files that are necessary to set up the infrastructure:

  • TurboStreamsViewResolverConfiguration.java – Registers an additional Thymeleaf View Resolver for the specialized Content-Type that Turbo-Streams is using. This way the Content-Negotiation of Spring WebMVC picks according to the Accept Header of the Client and responds with the right Content-Type automatically (i.e. we can simply return a view Name from the @Controller and Spring/Thymeleaf will pick up the correct view and Content-Type Response)
  • WebSocketConfiguration.java – registers our plain vanilla Websocket Handler to the URL expected in the frontend. As we do not want complex integration, we avoid the whole STOMP / SockJS Setup and just do simple Websockets.
  • TaskSchedulerConfiguration.java – since we use @Scheduled in some controllers, but do not use Stomp, we need to provide a custom Setup here, otherwise the Stomp integration fails with a missing bean.

other interesting Code

  • MessagesController.java – handles all the dynamic requests for data in the Turbo-Frames pages. It usually redirects to the origin page, when not a more detailed response is necessary
  • TurboStreamWebsocketHandler.java – a minimalistic Websocket Handler that is simply used to send turbo-streams updates to the Client. In a real application you would want to provide access to this component, so other Parts of the application could provide their content to this. Also note, that in a real setup one would need to handle more than a single WebSocketSession
  • TurboStreamSSEController.java – a simple implementation of a RequestController that uses SSE to do the communication with the client.

Showcased features

  • Navigation with Turbo Drive is enbled (visible through the progress bar and the fact that Originator for any Request in the Dev-Network Panel is: turbo.js)
  • Simple interaction of turbo-frames: only a part of a page is updated
  • Deferred loading of content with turbo-frames
  • interacting with other turbo-frames (trigger a request from a different part of the page than the one that is updated)
  • breaking free from a turbo-frame (navigating from inside a frame in a way that the whole window is replaced)
  • Using turbo-streams as a response to a normal form POST to update multiple elements on a page
  • Using turbo-Streams over Websockets to live-update a page (and Stimulus for the Client-Side Dynamic)
  • Using turbo-Streams over Websockets to live-update a page triggered through a Custom Element
  • Using turbo-Streams over SSE to live-update a page (and Stimulus for the Client-Side Dynamic)