playframework/play — pull request #391 by DougC (2011-11-30 09:59:49+00:00)
Title: 1.2.x

This is my first pull request, not just to playframework, but ever so be gentle with me if I've messed anything up :-)

[#806] This is a fix to allow Play to run in precompiled mode without the template sources needing to be present. In fact, the entire app/views directory can be removed as long as the templates have been precompiled.

With this fix I have concentrated on minimising the amount of code that I needed to change, and all the changes are isolated within TemplateLoader.java. The handling of precompiled templates was already a bit clunky, and this means the fix is also a bit of a hack, but in order to get a cleaner solution I'd need to make much more extensive changes and, as this is my first change to Play, I'd rather avoid that for the moment. I may attempt a cleaner fix later on.

The key things which I needed to change were:

a) TemplateLoader.load(String) scans the Play.templatePath list to try and find the source file for the template. If it doesn't find it, it never calls TemplateLoader.load(VirtualFile), which is the method that does the precompiled handling.

b) When the app/views directory is missing from the application root, Play.init does not add it to the templatePath list. This means that it wasn't included in the list of directories searched by TemplateLoader.load(String). In order to compensate for that, I now add app/views back into (a copy of) the template path in TemplateLoader.load(String). I could fix this in Play.init by adding "app/views" to the list regardless of whether it exists, but I didn't want to make any changes outside TemplateLoader if I could help it.

c) I've added logic to TemplateLoader.load(String) so that if it can't find the source for the template, it checks to see if the precompiled method is present. If so, it makes the call to TemplateLoader.load(VirtualFile) that was being omitted before.

d) TemplateLoader.load(VirtualFile) was trying to load the source text of the template file regardless of whether it was loading the precompiled version. I presume this would be used for quoting source lines when reporting errors. I've changed it so that it only tries to load the source if the source file is present. If the source file is not present, it simply uses an empty string when creating the GroovyTemplate.

e) I've extracted a method to generate the precompiled name from the template name as I needed to re-use the logic in TemplateLoader.load(String).