Spring Boot - How to skip cache thyemeleaf template, js, css etc to bypass restarting the server everytime

The default template resolver registered by Spring Boot autoconfiguration for ThyemeLeaf is classpath based, meaning that it loads the templates and other static resources from the compiled resources i.e, /target/classes/**.



To load the changes to the resources (HTML, js, CSS, etc), we can
  • Restart the application every time- which is of course not a good idea!
  • Recompile the resources using CTRL+F9 on IntelliJ or (CTRL+SHIFT+F9 if you are using eclipse keymap) or simply Right Click and Click Compile
  • Or a better solution as described below !!

Thymeleaf includes a file-system based resolver, this loads the templates from the file-system directly not through the classpath (compiled resources).

See the snippet from DefaultTemplateResolverConfiguration#defaultTemplateResolver

@Bean
public SpringResourceTemplateResolver defaultTemplateResolver() {
 SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
 resolver.setApplicationContext(this.applicationContext);
 resolver.setPrefix(this.properties.getPrefix());

Where the property prefix is defaulted to "classpath:/template/". See the snippet ThymeleafProperties#DEFAULT_PREFIX
public static final String DEFAULT_PREFIX = "classpath:/templates/";


The Solution:

Spring Boot allows us to override the property 'spring.thymeleaf.prefix' to point to source folder 'src/main/resources/templates/ instead of the default "classpath:/templates/" as folllows.

In application.yml|properties file:
spring:
    thymeleaf:
        prefix: file:src/main/resources/templates/  #directly serve from src folder instead of target

This would tell the runtime to not look into the target/ folder. And you don't need to restart server everytime you update a html template on our src/main/resources/template

What about the JavaScript/CSS files?

You can further go ahead and update the 'spring.resources.static-locations' to point to your static resource folder (where you keep js/css, images etc)
spring:
    resources:
        static-locations: file:src/main/resources/static/ #directly serve from src folder instead of target        cache:
          period: 0

The full code:

It a good practice to have the above configuration during development only. To have the default configuration for production system, you can use Profiles and define separate behaviour for each environment.

Here's the full code snippets based on what we just described!

Project Structure:

Pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>my-sample-app</artifactId>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <!-- the basic dependencies as described on the blog -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <build>
        <finalName>${build.profile}-${project.version}-app</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <profiles>

        <!-- Two profiles -->

        <profile>
            <id>dev</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <spring.profiles.active>dev</spring.profiles.active>
                <build.profile>dev<build.profile>
            </properties>
        </profile>

        <profile>
            <id>prod</id>
            <properties>
                <spring.profiles.active>prod</spring.profiles.active>
                <build.profile>prod<build.profile>
            </properties>
        </profile>

    </profiles>

</project>

The property files (yml)

application-dev.yml
spring:
    profiles:
        active: dev
    thymeleaf:
        cache: false        prefix: file:src/main/resources/templates/  #directly serve from src folder instead of target    resources:
        static-locations: file:src/main/resources/static/ #directly serve from src folder instead of target        cache:
            period: 0
 
application-prod.yml (doesn't override anything)
spring:
    profiles:
        active: prod



Hope this helps!