Efficient webjars version resolution natively in Spring
See original GitHub issueSpring (MVC and Webflux) has a ResourceResolver
abstraction that can be used to resolve the versions in webjars, avoiding the need to maintain the version explicitly in 2 or more places (build file and HTML source). E.g. (from Petclinic):
<script src="/webjars/jquery/jquery.min.js"></script>
Resolves to classpath:/META-INF/resources/webjars/jquery/<version>/jquery.min.js
at runtime.
Spring Boot carries the responsibility of configuring the resource resolver, and currently it uses the webjars-locator-core
(https://github.com/webjars/webjars-locator-core) library to do that, so version resolution only works if that library is on the classpath. The WebJarsAssetLocator
from that library has a very broad and powerful API for locating files inside webjars, but there are some issues, namely:
- It is fairly inefficient, since it scans the whole
/META-INF/resources/webjars
classpath on startup (in a constructor!). - It has 2 awkward dependencies (github classpath scanner and jackson)
- It doesn’t work in a native image (https://github.com/spring-projects-experimental/spring-native/issues/157) because of the classpath scanning
But we don’t need webjars-locator-core
to just do version resolution, which is all Spring Boot offers, because webjars have a very well-defined structure. They all have a pom.properties
with the version in it, and they only use a handful of well-known group ids, so they are easy to locate. It might be a good idea to implement it in Framework, since it is so straightforward and only depends on reading resources from the classpath.
All of the issues above could be addressed just by providing a simpler version resolver natively (and configuring the resource config in a native image with a hint).
Issue Analytics
- State:
- Created 2 years ago
- Comments:23 (19 by maintainers)
Here’s an implementation (with no caching or any optimizations):
and here’s how to install it in a Spring Boot application:
(See it work in the Petclinic here: https://github.com/dsyer/spring-petclinic/blob/webjars/src/main/java/org/springframework/samples/petclinic/system/WebJarsVersionResourceResolver.java.)
@dsyer said “It is fairly inefficient”, which is very polite of him but I want to stretch on that a bit:
I was profiling a test-suite the other day whose allocations flame-graphs have ~63% of the frames only matched by classgraph scanning that is entirely caused by resolving/locating webjars.
Now of course this doesn’t translate to CPU 1:1 where it’s only ~10%, but notice how much is spent in G1 garbage collection on top of that (unsurprisingly).
A test-suite is obviously not a production environment where this isn’t as noticeable. But tests usually start several contexts and the general startup routine is executed more often usually. So working on improving that inside Spring directly might be a tremendous boost in developer productivity for certain projects, because it will directly impact test suites, startups etc…