Vaadin 10 and static resources

Leif Åstrand
Leif Åstrand
On Jul 9, 2018 8:21:00 AM

Vaadin 10 makes some changes to the way it loads static resources, such as application templates, custom styles and any additional JavaScript files. The gist of it is that such files should be put in src/main/webapp/frontend/ when building a .war file and src/main/resources/META-INF/resources/frontend/ when building a .jar file.

Web fragments let you put static resources in .jar files

Since the beginning of time, it has been possible to put static files in the root of a .war archive. The servlet container serves such files as static files as long as there isn't a servlet for the same URL. Since the beginning of Maven, files from src/main/webapp/ have been packaged into the root of the .war file.

Previously, various workarounds have been needed to make it possible for libraries used by the application to contain their own static files. Vaadin has been using a special /VAADIN/ directory and custom logic in the servlet that looks for that directory on the classpath.

This is no longer needed with the web fragments feature that was introduced in version 3.0 of the Servlet specification. The basic idea is that files in META-INF/resources/ inside any .jar file in the application's WEB-INF/lib/ directory will also be available as static files in the same way as files from the root of the .war archive. Expressed based on Maven conventions, this means that the files would be in src/main/resources/META-INF/resources/. A common mistake to look out for when creating your own static files is that either of the resources/ segments is forgotten!

Flow does magic things with the frontend directory

Another piece of the puzzle is the way Vaadin Flow uses different variants of the application's frontend/ directory. The reason for this that some older browsers do not support the modern JavaScript variant that is called ES6, but older ES5 version. Web Components on the other hand are based on modern web standards and require ES6 functionality. For the old browsers, it's necessary to transpile(automatically rewrite) the JavaScript code to only use features from ES5. On the other hand, transpiled files would cause unnecessary overhead in modern browsers, so Vaadin serves the most optimal files for the browser accessing the files.

Another related thing is that Web Components are typically split out to multiple small files for each component, and those files also contain lots of code comments. This is no problem during development when the files are loaded only over the local network, but it causes overhead for production usage over slower networks.

To deal with this whole mess, Flow uses three different variants of the application's frontend files, i.e. the application's own templates as well as reusable Web Components from Bower.


  • The frontend/ directory contains the original files for smooth local development without any extra build steps.
  • The frontend-es6/ directory contains minified files that have also been bundled together into a few big files instead of lots of small ones.
  • The frontend-es5/ directory has received the same treatment as frontend-es6/, but in addition all the JavaScript is rewritten to only use features available in ES5.

Minifying, bundling and transpilation is only needed for production use (or during development when you test with an older browser) and is performed by the vaadin-maven-plugin when you build using the productionMode profile in Maven.

Whenever your Java code uses a resource annotation such as @HtmlImport("src/views/reviewslist/reviews-list.html"), Flow will add the right frontend directory prefix before sending the URL to the browser. If bundling is used and the file is included in a bundle, the URL of that bundle is used instead. Resource annotations are by default assuming your files are inside the frontend/ directory. If you want to load to resources from some other location, you can define the resource as an absolute URL (i.e. starting with / or a protocol such as http://) or use the special context:// pseudo protocol, e.g. @StyleSheet("context://styles.css"), which resolves relative to the context path of the web application.

Learn more about Vaadin Flow

Leif Åstrand
Leif Åstrand
Leif Åstrand keeps an eye on the overall architecture of the Vaadin platform. He knows a thing or two about how Vaadin, Web Components, and the internet works.
Other posts by Leif Åstrand