DEV Community

Thomas Schühly
Thomas Schühly

Posted on

Fixing the Spring Boot LiveReload Server with Gradle for Thymeleaf and TailwindCSS

LiveReloading with Thymeleaf

I couldn't get Live Reload with Spring Boot and Thymeleaf to work. The problem seems to be so widespread that even @wimdeblauwe the author of Taming Thymeleaf uses gulp/npm to get Live Reloading working.

I thought why do we need to use Javascript to get our Spring Boot Developer Experience up to par with the big Javascript Frameworks? We have a perfectly fine Build Tool with Gradle!

LiveReload.js

First we need to include a script tag which points to the LiveReload Server:

<script src="http://localhost:35729/livereload.js"></script>
Enter fullscreen mode Exit fullscreen mode

Gradle Sync

The plan is the same as with the npm scripts. Sync the templates into the build output so LiveReload triggers properly. This is done with the Gradle Sync Task:

// build.gradle.kts
tasks.register("sync"){
    inputs.files("./src/main/resources/static","./src/main/resources/templates",)
    doLast {
        sync {
            from("./src/main/resources/static")
            into("build/resources/main/static")
        }
        sync {
            from("./src/main/resources/templates")
            into("build/resources/main/templates")
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Now start a continuous build with:

.\gradlew -t sync
Enter fullscreen mode Exit fullscreen mode

Each time one of the inputs.files directory changes the sync task is rerun and LiveReload works.

Tailwind CSS

To use TailwindCSS we use the node-gradle plugin and create a npx task:

// build.gradle.kts
plugins {
    ...
    id("com.github.node-gradle.node") version "3.4.0"
}

tasks.register<com.github.gradle.node.npm.task.NpxTask>("tailwind"){
    command.set("tailwindcss")
    args.set(listOf("-i", "./src/main/resources/static/styles.css",  
        "-o" ,"./src/main/resources/static/output.css", "--watch"))
}
Enter fullscreen mode Exit fullscreen mode

We then need to create a package.json:

{
  "devDependencies": {
    "@tailwindcss/forms": "^0.5.2",
    "tailwindcss": "^3.1.4"
  }
}

Enter fullscreen mode Exit fullscreen mode

Add a tailwind.config.js:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{html,js}"],
}

Enter fullscreen mode Exit fullscreen mode

Add a styles.css in resources/static/:

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

and include output.css in our html:

<link href="/output.css" rel="stylesheet">
Enter fullscreen mode Exit fullscreen mode

Now we can start the tailwind npx task in a new terminal:

.\gradlew tailwind
Enter fullscreen mode Exit fullscreen mode

And it works:

You can see an example at: github.com/tschuehly/thymeleaf-livereload-gradle

Top comments (1)

Collapse
 
djpeach profile image
Daniel Peach

The gradle task for the tailwindcss command with --watch does not work for me. Even when using your code. Wish it did but, I have to run tailwindcss seperately for now.

I played around with Gradle's --continuous mode, and have to say, not a fan. I can save, click off, and reload, faster than Gradle can pick up the changes and do it for me. May be because I am on a Mac, and apparently the watcher Gradle uses on Mac can be slow.

For now, I am just running tailwindcss seperately, and relying on the build in livereload with SpringBoot. Its fast and easy.

When working on templates, I start up tailwind from my package.json, and start up the SpringBoot app from the Application File, or using bootRun.

I didn't have to add any new tasks to my build.gradle.kts. I may add some for build-time for pushing to production or something, but for development, it was not necessary.

Some gotchas:

  • tailwindcss in watch mode will not remove unused css. You will need to re-run for JIT engine to remove those.
  • it seems SpringBoot is issuing a full restart when making changes to templates and css. Unsure of why that is. Should just be doing a live-reload.