{"id":20138148,"url":"https://github.com/innoq/hotwire-demo","last_synced_at":"2025-04-09T18:08:41.764Z","repository":{"id":54973804,"uuid":"330664608","full_name":"innoq/hotwire-demo","owner":"innoq","description":"Showcasing the integration of the different hotwire.dev parts into a typical Spring Boot Webapp","archived":false,"fork":false,"pushed_at":"2023-03-07T00:06:44.000Z","size":893,"stargazers_count":68,"open_issues_count":6,"forks_count":6,"subscribers_count":68,"default_branch":"main","last_synced_at":"2025-03-23T20:04:19.516Z","etag":null,"topics":["hotwire","hotwire-turbo","java","spring","spring-boot","spring-mvc","thymeleaf"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/innoq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-18T12:49:33.000Z","updated_at":"2024-12-11T08:00:55.000Z","dependencies_parsed_at":"2024-11-13T21:37:14.594Z","dependency_job_id":"af2f48f3-b82c-4722-be10-678dc295238a","html_url":"https://github.com/innoq/hotwire-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/innoq%2Fhotwire-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/innoq%2Fhotwire-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/innoq%2Fhotwire-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/innoq%2Fhotwire-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/innoq","download_url":"https://codeload.github.com/innoq/hotwire-demo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248084332,"owners_count":21045125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hotwire","hotwire-turbo","java","spring","spring-boot","spring-mvc","thymeleaf"],"created_at":"2024-11-13T21:35:03.099Z","updated_at":"2025-04-09T18:08:41.744Z","avatar_url":"https://github.com/innoq.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hotwire DEMO\nA simple Spring Boot Application to showcase the integration of [Hotwire](https://hotwire.dev) into a 'normal' Spring Boot Webapplication\n\n## Getting started\n\n1. Build the JS Parts\n```\ncd src/main/js\nnpm install\nnpm run build \u0026\u0026 npm run deploy\n```\n\n2. Run the application\n```\n./mvnw clean install spring-boot:run\n```\n\nPoint your browser to [http://localhost:8080](http://localhost:8080)\n\n## under the hood\n\n### JS\n\nThe little JS Code that is necessary is built in `src/main/js` using [snowpack](https://snowpack.dev), to add minimal overhead. The necessary call is wired to the `build` target of npm.\n\nSince we needed two Button Handlers for the Turbo Streams examples, this also includes a short [Stimulus](https://stimulus.hotwire.dev/) Usage to hook up Controllers to those Buttons. Have a peek into `ConnectSSEController.js` and `ConnectWebsocketController.js` if you're interested.\n\nThe `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)\n\nIn order for the demo to run properly you need to run `npm run build \u0026\u0026 npm run deploy` at least once, so the necessary files are created.\n\n\n### Java\n\nThe Spring app is mostly plain vanilla Spring Boot/WebMVC with Thymeleaf for rendering templates.\n\n\n#### Spring Config\n\nThere are a few Configuration Files that are necessary to set up the infrastructure:\n\n- `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)\n- `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.\n- `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.\n\n#### other interesting Code\n\n- `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\n- `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`\n- `TurboStreamSSEController.java` – a simple implementation of a `RequestController` that uses [SSE](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) to do the communication with the client.\n\n## Showcased features\n\n- 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`)\n- Simple interaction of turbo-frames: only a part of a page is updated\n- Deferred loading of content with turbo-frames\n- interacting with other turbo-frames (trigger a request from a different part of the page than the one that is updated)\n- breaking free from a turbo-frame (navigating from inside a frame in a way that the whole window is replaced)\n- Using turbo-streams as a response to a normal form `POST` to update multiple elements on a page\n- Using turbo-Streams over Websockets to live-update a page (and Stimulus for the Client-Side Dynamic)\n- Using turbo-Streams over Websockets to live-update a page triggered through a Custom Element\n- Using turbo-Streams over SSE to live-update a page (and Stimulus for the Client-Side Dynamic)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finnoq%2Fhotwire-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finnoq%2Fhotwire-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finnoq%2Fhotwire-demo/lists"}