spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.57k stars 40.55k forks source link

Thymeleaf templates cache even when spring.template.cache: false #34

Closed checketts closed 10 years ago

checketts commented 11 years ago

When editing Thymeleaf templates, a server restart is required to view the updates.

Even with the following setting in application.properties:

# Allow Thymeleaf templates to be reloaded at dev time
spring.template.cache: false

To reproduce: With spring-boot-sample-web-ui, run it with mvn spring-boot:run and edit any of the templates, they don't reload after server has been started.

ukitzmann commented 11 years ago

You can use this to disable the Thymeleaf cache:

spring.thymeleaf.cache: false
checketts commented 11 years ago

This ticket is noting that even when using that property, they are being cached.

dsyer commented 11 years ago

mvn spring-boot:run probably runs from the compiled jar. To use spring.template.cache: false effectively you need to launch from an IDE. Does that make sense? It seems to work for other people.

dsyer commented 11 years ago

I guess if you mvn package you will get the source files copied into the classpath of the running process. If that works I'm not sure what else we can do. Did you try it?

yanhua365 commented 11 years ago

It works!

I user IntelliJ Idea debug the application.

After add application.properties with:

spring.thymeleaf.cache: false

Then,after edit html template, must use CTRL+F9 to make the project.

In this way,it works fine for me.

MattFriedman commented 9 years ago

I run the application from main() in Idea IDE. I set the application.properties as stated above.

If I'm using jsp then I can expect changes to the jsp files to be visible immediately without recompiling.

I think the issue here is that there is an expectation that the thymeleaf templates will have the same behaviour. This does not appear to be the case.

Is it possible to have changes to the th templates visible any time they are changed, without any recompiling or rebuilding of the project?

The point is that front-end developers need to make tons of changes to templates and view the results often. Having to recompile every time is a ton of overhead for a front-end developer so they want to avoid this.

dsyer commented 9 years ago

Well it works for other people so you must be doing something different, I'd say. Did you read everything above? E.g. you seem to be using the wrong property name for the cache setting.

MattFriedman commented 9 years ago

Hi Dave,

I have done the following: I read all the posts. I put the system in debug (running from main()) and verified that the TemplateResolver/ViewResolver had caching set to false. I used both properties mentioned above, both set to false. I tried changing the template and opened the page in two separate browsers to see if it was the browser that was caching the older version but this is not the case. I checked using curl as well.

I think what it comes down to is how you define: "it works"

Above, yanhua365 says "Then,after edit html template, must use CTRL+F9 to make the project"

For me, "it works" means: change the template => refresh browser => changes are visible.

So yanhua365 is correct, it does work in the way he describes. However, as far as I can determine, it does not work in the way I am describing.

I'm just trying to point out that the intermediate step of having to rebuild is a problem as it adds a boatload of overhead to the development flow for front-end developers. Front-end developers are constantly making changes and then refreshing the page to check the result. (to the point of developing repetitive stress injuries) Adding an intermediate step is a problem from that perspective.

I don't know if it possible for it to work in the way I'm describing, but if it is it would be a great improvement.

dsyer commented 9 years ago

"CTRL+F9" must be something you can automate (build on save or something). Other IntelliJ users manage it, so it must be possible (cc @snicoll in case he knows what the incantation is).

snicoll commented 9 years ago

https://www.jetbrains.com/idea/documentation/migration_faq.html

You can enable automatic compilation on every save (or autosave). To do that, turn on the Make project automatically option on the Compiler page in the Settings / Preferences dialog (File | Settings | Compiler on Windows or Linux, or IntelliJ IDEA | Preferences | Compiler on Mac OS X).

@MattFriedman if you want to discuss this further, please create a separate issue.

pieterdegraeuwe commented 9 years ago

For the ones that are struggling with this too. Be sure that your application.properties is on the right location! (more on this here) When you have in your resources directory also a sub directory 'templates', it can be quickly overseen that your application.properties is not IN, but on the same level as the 'resourses' directory. At least this was the case for me on a late evening.... I discovered it by putting the application.properties in a config directory... then the reloading did suddenly work.. This lead me to see that the other application.properties was not found, since it was not in the resources directory...

amr commented 9 years ago

@MattFriedman The default template resolver registered by spring is classpath based, meaning that it loads the templates from the compiled resources. That's why it requires a recompilation. Thymeleaf includes a file-system based resolver, this loads the templates from the file-system directly not through the classpath (compiled resources). Spring Boot allows us to override the default resolver by making a bean with the name defaultTemplateResolver, here is a full example:

@Configuration
public class ThymeleafConfiguration {
  @Bean
  public ITemplateResolver defaultTemplateResolver() {
    TemplateResolver resolver = new FileTemplateResolver();
    resolver.setSuffix(".html");
    resolver.setPrefix("path/to/your/templates");
    resolver.setTemplateMode("HTML5");
    resolver.setCharacterEncoding("UTF-8");
    resolver.setCacheable(false);
    return resolver;
  }
}

With this, I basically Ctrl+S and refresh the browser. A better variation would be one that uses ThymeleafProperties, like that:

@Configuration
public class ThymeleafConfiguration {
  @Inject
  private ThymeleafProperties properties;

  @Value("${spring.thymeleaf.templates_root:}")
  private String templatesRoot;

  @Bean
  public ITemplateResolver defaultTemplateResolver() {
    TemplateResolver resolver = new FileTemplateResolver();
    resolver.setSuffix(properties.getSuffix());
    resolver.setPrefix(templatesRoot);
    resolver.setTemplateMode(properties.getMode());
    resolver.setCharacterEncoding(properties.getEncoding());
    resolver.setCacheable(properties.isCache());
    return resolver;
  }
}

This would work with an application-dev.yml like:

spring:
    thymeleaf:
      mode: HTML5
      cache: false
      templates_root: src/main/resources/templates/

In my application, I annotate that resolver with @Profile(Constants.SPRING_PROFILE_DEVELOPMENT) to limit its use to development. That's why I also set the caching to false in the configuration file (it's -dev only). In production I use the default classpath-based loader.

dsyer commented 9 years ago

You should be able to just use the default classpath loader as long as you are running in debug mode (and your IDE is configured to copy resources on save - Eclipse does this out of the box).

thesurlydev commented 9 years ago

For other folks that might run into this issue. I had the same problem until I realized that IntelliJ's key mapping for Ctrl-F9 was not actually doing what it was supposed to (Make Project). You can verify this in a couple of ways:

  1. monitor the timestamp of a Thymeleaf template in target/classes/templates after you make a change and use Ctrl-F9.
  2. make a change to a template, then use the Build > Make Project via the main menu.

The fix for my particular case was to remap the keyboard shortcut for "Make Project". After I did this I was able to make changes to my templates, use my new keyboard shortcut for "Make Project", then reload the browser to see the changes.

jgon commented 9 years ago

@amr : Thank you. The solution using the ThymeleafConfiguration worked perfectly. I just had to replace @Inject by @Autowired in my case.

giovannicandido commented 8 years ago

In my application-development.yml:

resources:
  projectroot: /Users/giovanni/Projects/projectName
spring:
   thymeleaf:
     cache: false
     prefix: file:///${resources.projectroot}/server/src/main/resources/templates/

This way in development it use the direct files, and in production the classpath Note: There is a subproject named server in the projectName project root

henryabra commented 8 years ago

@giovannicandido Thanks for the tip. One note though, ${resources.projectroot} did not work for me but ${user.dir} worked like a charm. Cheers

snicoll commented 8 years ago

@henryabra ${resources.projectroot} is a custom key that is defined in the same yml file (see the two first line).

henryabra commented 8 years ago

@giovannicandido You are absolutely correct.

oak1980 commented 7 years ago

Springboot with IntelliJ and configurations in src/main/resources/application.properties I put in the following relative path, and started the Application.main(...) from IntelliJ:

# Templates reloading during development
spring.thymeleaf.prefix=file:src/main/resources/templates/
spring.thymeleaf.cache=false

# Static resources reloading during development
spring.resources.static-locations=file:src/main/resources/static/
spring.resources.cache-period=0
checketts commented 7 years ago

@oak1980 You are using a debug configuration and hitting CTRL-F9? (See https://github.com/spring-projects/spring-boot/issues/34#issuecomment-24964507) What versions of SpringBoot are you using if you believe it is a regression?

oak1980 commented 7 years ago

With this approach, I don't need to press CTRL-F9.

checketts commented 7 years ago

Ah so you are reporting an alternative approach that works for you and avoids the need to rebuild in IntelliJ.

It is good to call out that you wouldn't want to check it spring.resources.static-locations=file:src/main/resources/static/ in your application.yml, and instead set it via a run config in intelliJ so you don't accidentally check it in (or perhaps set it in a profile specific file)

PhaneendraNakkala commented 7 years ago

@oak1980 you are awesome! that works like charm.

anuragphadke19 commented 5 years ago

Springboot with IntelliJ and configurations in src/main/resources/application.properties I put in the following relative path, and started the Application.main(...) from IntelliJ:

# Templates reloading during development
spring.thymeleaf.prefix=file:src/main/resources/templates/
spring.thymeleaf.cache=false

# Static resources reloading during development
spring.resources.static-locations=file:src/main/resources/static/
spring.resources.cache-period=0

If someone else drop's by this long-closed issue, the parameter should be(as of Spring Boot 2.0.5 release) spring.resources.cache.period=0

attacomsian commented 5 years ago

I recommend using Gulp to automate templates and resources reload. Following is a little Gulp task that does the magic for me:

var gulp = require('gulp'), 
    watch = require('gulp-watch');

gulp.task('watch', function () {
    return watch('src/main/resources/**/*.*', () => {
            gulp.src('src/main/resources/**')
                //replace with build/resources/main/ for netBeans
                .pipe(gulp.dest('out/production/resources/')); 
    });
});

gulp.task('default', ['watch']);

I wrote a short blog post on this topic as well.

pdurejachd commented 4 years ago

A working solution is to override the defaultTemplateResolver by using a file system based resolver:

application.properties

spring.thymeleaf.cache=false
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.templates_root=src/main/resources/templates/

Application class

@SpringBootApplication
public class MyApplication {

    @Autowired
    private ThymeleafProperties properties;

    @Value("${spring.thymeleaf.templates_root:}")
    private String templatesRoot;

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Bean
    public ITemplateResolver defaultTemplateResolver() {
        FileTemplateResolver resolver = new FileTemplateResolver();
        resolver.setSuffix(properties.getSuffix());
        resolver.setPrefix(templatesRoot);
        resolver.setTemplateMode(properties.getMode());
        resolver.setCacheable(properties.isCache());
        return resolver;
    }
}
waltervi commented 3 years ago

Springboot with IntelliJ and configurations in src/main/resources/application.properties I put in the following relative path, and started the Application.main(...) from IntelliJ:

# Templates reloading during development
spring.thymeleaf.prefix=file:src/main/resources/templates/
spring.thymeleaf.cache=false

# Static resources reloading during development
spring.resources.static-locations=file:src/main/resources/static/
spring.resources.cache-period=0

You saved my day buddy!

dtonhofer commented 1 year ago

The latest configuration names seem to be as follows, based off Spring Boot 3.1.0:

Unchanged:

# Templates reloading during development
spring.thymeleaf.prefix=file:src/main/resources/templates/
spring.thymeleaf.cache=false

Changed:

# Static resources reloading during development
spring.web.resources.static-locations=file:src/main/resources/static/
spring.web.resources.cache.period=0

Or in YAML (application.yml):

spring:
  thymeleaf:
    # Template reloading during development
    prefix: file:src/main/resources/templates/
    cache: false
  web:
    resources:
      # Static resource reloading during development
      static-locations: file:src/main/resources/static/
      cache:
        period: 0
alfuguo commented 5 months ago

The latest configuration names seem to be as follows, based off Spring Boot 3.1.0:

Unchanged:

# Templates reloading during development
spring.thymeleaf.prefix=file:src/main/resources/templates/
spring.thymeleaf.cache=false

Changed:

# Static resources reloading during development
spring.web.resources.static-locations=file:src/main/resources/static/
spring.web.resources.cache.period=0

Or in YAML (application.yml):

spring:
  thymeleaf:
    # Template reloading during development
    prefix: file:src/main/resources/templates/
    cache: false
  web:
    resources:
      # Static resource reloading during development
      static-locations: file:src/main/resources/static/
      cache:
        period: 0

Thank you @dtonhofer, still working in 2024~ 👍