Modular Web UI
This document is intended to serve as a starting point for a discussion on how (and why) we might want to introduce modularity to the frontend.
Background
Currently Amdatu provides very little support for managing resources on the frontend side. The amdatu-webresources bundle provides an easy way for a bundle to declare static web resources. This provides a very good solution for building simple websites. You update a resource in your bundle and the change is reflected in your browser right away. Moreover, you can make your UI resources modular by including resources that belong to a specific feature in their own bundle.
However, this approach doesn't really work for real world, complex web applications mainly for the following reasons:
- Modern web applications often do not use CSS or JS directly but some other language that needs to be compiled before it can be accessed from a browser (TypeScript, CofeeScript, SCSS, LessCSS and such)
- Frontend resources need to be minified before they can be deployed to the production environment
For these reasons and possibly more, the workflow used for building web apps is usually something like this:
- All frontend code is written in the same project, and effectively in the same OSGi bundle
- A command line tool such as gulp is run in the background, performing the necessary resource compilations
- The compiled resources are then added to the bundle using amdatu-webresources.
While this approach does work, it introduces a great deal of complexity to both the development and deployment workflow:
- The developer must install and configure (either manually or using helper scripts) third party tools such as NodeJS, ruby, gulp, grunt and such. The installation process is quite different in each operating system.
- In order to simplify the development workflow, a separate web server (such as gulp) is used so that changes in code are automatically reflected in the UI. While this works, it also makes it impossible to separate UI resources to multiple bundles. Doing so would require running multiple gulp instances which is not a viable option.
So do we need modularity on the frontend ?
Large OSGi projects currently enjoy a great deal of flexibility on the backend side. Being able to wrap functionality related to a given feature in a separate bundle is essential to the OSGi development style. Being able to do the same also for frontend code makes sense. Currently many projects use RequireJS, which already provides very good support for dividing frontend code to reusable modules and resolving them when necessary. Making it possible to define that code in multiple bundles and compile it (to JS & CSS) at runtime would fill the gap, allowing developers to write truely modular frontend applications.
Possible Implementations
Currently amdatu-webresources serves the resources directly from the bundle declaring them. It may be good to change that so that some (or possibly all) resources from all registered bundles are copied to the bundle cache of the amdatu-webresources bundle itself and served from there. The advantage in using this approach is that modularity is made possible since resources can reside in any bundle, and all resources are concentrated at runtime at the same place, where it may be processed and converted as necessary.
Resource Compilation
It's possible to support resource compilation at runtime by executing the compilation directly from java, mimicking the behavior of tools such as grunt, and compiling resources when the bundle is modified. While this is far from trivial to implement, there is already quite good support in the JVM for script execution, and it seems like Oracle is pushing the JVM forward as a multi language runtime, especially in the upcoming release of jDK8. I've looked into the following topics,and wrote a small demo ((https://bitbucket.org/danbaryak/amdatu-spa-poc) illustrating it.
- Typescript - There is already an existing java wrapper for typescript compilation (typescript4j). I've played around with it in the demo project and managed to get it to compile a ts file, although compilation was painfully slow. The typescript4j project uses rhino to execute typescript compilation, which is known to be slow. However, JDK8 includes a brand new javascript engine called nashorn which is a complete rewrite, and it appears that the Oracle guys are using the typescript compiler as a benchmark to improve its performance. According to this very recent article, they made considerable progress in achieving near native performance. Furthermore, they are going to open source nashorn typescript for everyone to use.
- SCSS - there is an existing wrapper of the sass compiler that uses JRuby and includes all the Gems necessary to run it. I haven't tested it's performance, but from looking around, JRuby performance is generally considered similar to using native ruby.
Another option would be to wrap an existing tool, such as grunt or gulp and invoke it at runtime. The advantage of this is clear, This is tricky though as it means we would have to install the tool and maintain it also on the deployment machine.