rocker icon indicating copy to clipboard operation
rocker copied to clipboard

Compilation and Template class loading at Runtime

Open hofmanndavid opened this issue 7 years ago • 8 comments

Is there a chance we can make Rocker runtime API to compile templates on the fly and load the compiled classes as BindableRockerModel?

The api should be similar to

Rocker.compileAndLoad(name, template)

name should be the name of the template and template can be loaded from filesystem, classloader or as a String

Such a feature exists in a similar Java Template Engine called Rythm

I suppose that the JVM Metaspace will be affected for each class reloading but besides that is there a reason why this is a bad idea?

hofmanndavid avatar Feb 16 '18 18:02 hofmanndavid

+1

JarekToro avatar Feb 16 '18 18:02 JarekToro

Only risk is the usual JVM + class reloading issues that many other apps & platforms have as well. Obviously also some small performance drawbacks to reflection-based property settings, etc., but those are minimal compared to the ease of use.

Everything should already exist for this to work, I just have never tried it in production or documented it how you'd package it up. But the hot reloading feature of Rocker already lets this work in development, no reason it can't be used in production.

You'd need to include rocker-compiler and rocker-runtime in your app. Its critical to load templates using strings for views using com.fizzed.rocker.Rocker.template() method and then dynamically binding values before you render it. The other caveat (and maybe code to polish up this use case), would be supplying Rocker and RockerReloadingBootstrap with enough info to make sure it knows where to find templates. During development, the maven plugin drops in a properties file to your classpath (classes build dir) that includes that information, but in production you'd probably want a different solution (maybe).

Would love your help documenting / submitting PRs for polishing this use case up since I think its a common question.

jjlauer avatar Feb 16 '18 19:02 jjlauer

This is perfect then. I was looking at rocker-compiler and the rocker-maven-plugin and I saw it only generates the Java source code clases. Then I thought I could use the Java Runtime Compiler from Chronicle to compile at runtime and load the templates as instances of RockerTemplate.

Now that you mention that rocker-runtime can do that on it's own I'll dig more in the code and try to submit a PR in the coming days.

hofmanndavid avatar Feb 16 '18 19:02 hofmanndavid

In development mode it makes sense to asume that rocker-runtime will deal with templates available in the classpath via File. It asumes the compiler plugin is present and was correctly hooked to the compiling process.

However, to enable on-the-flight compilation and reloading for production usage it makes sense to do necessary refactors that allows for templates coming from the filesystem, the classpath or string values. This is for example if I don't want to rely on filesystem to store the templates. Does this assumption makes sense?

If so, I don't see how this can be done with small changes. The codebase asumes the template is present in the filesystem.

Will It will make sense to merge compiler and runtime in one project and provide different abstractions on the way templates are loaded to support the 3 usage scenarios? (compiling via compiler plugin, reloading compiled templates while in development and full on-the-flight compilation and reloading)

Should a simpler hack be made to support this issue?

hofmanndavid avatar Feb 28 '18 02:02 hofmanndavid

I won't be able to work on this until further notice.

hofmanndavid avatar Mar 02 '18 14:03 hofmanndavid

Merging the runtime & compiler together isn't an option IMHO. The compiler has a couple dependencies (e.g. ANTLR) that I don't want to force on users who simply use Rocker templates in the highest performance case -- where all compilation happens in development. That's why they were split up to begin with.

For on-the-fly compilation thru various mechanisms (disk, database, classpath, etc.), Rocker doesn't rely on the filesystem as much as I think you are suggesting. There are 3 areas for on-the-fly: 1) where Rocker finds templates to convert into .java code 2) converting .java files into .class files and 3) loading .class files. 1 and 3 should be pretty straightforward and I'm not sure I agree that any code currently in Rocker would make that difficult to switch to use InputStreams, etc. For 2, that may be easy/hard since a Java compiler is involved. Right now Rocker assumes there's a .java file on the filesystem to get it into a .class file on the filesystem, but obviously many other projects can do that in-memory or temporary files, so that should be doable too.

jjlauer avatar Mar 02 '18 14:03 jjlauer

Just a side remark: Tomcat uses ecj from eclipse (https://github.com/eclipse/eclipse.jdt.core) to compile JSPs on the fly. it's actually a reasonably small jar without any dependencies, and, as an added bonus, ecj is much more forgiving than the openjdk's javac and tries to produce something that runs even in presence of errors.

This also rises a question: how rocker compares to JSP (say, tomcat's jasper) performance wise? After all, JSP is a venerable patriarch of all java template engines and can be pretty fast if used properly.

oakad avatar Mar 08 '18 15:03 oakad

@oakad JSP doesn't compile down to a String or even anything close though. It actually outputs a Java servlet, which means it has to go through some overheads / hoops that Rocker doesn't.

re-thc avatar Jan 19 '19 13:01 re-thc