flow
flow copied to clipboard
Static resource cannot be found if it referenced from CSS with relative path
Description of the bug
If I place my static resource, say, image vaadin-logo.png into src/main/webapp/images/vaadin-logo.png and reference it from the styles.css of my custom theme, like shown below:
.vaadin-logo {
background-image: url("./images/vaadin-logo.png");
}
it gives 404 NOT FOUND response from server, so Flow doesn't resolve the URL properly.
However, if I put this image file into ${project.root}/frontend/themes/my-theme/images/, it would work as expected.
Also, if I remove the . and set the URL as an absolute path, it also works: url("/images/vaadin-logo.png").
I expect that the relative URL should properly be resolved by Flow and properly return the resource.
This issue only occurs when the pre-compiled production bundle is used in Vaadin 24.1 pre. Not reproducible with production build and dev mode in 24.1 pre and with older versions.
UPD: reproduces also with Vaadin 24.0.5 with pre-compiled dev bundle:
java.lang.IllegalStateException: Asset '/images/vaadin-logo.png' is not found in project frontend directory, default development bundle or in the application bundle 'src/main/dev-bundle/assets/'.
Verify that the asset is available in 'frontend/themes/my-theme/' directory and is added into the 'assets' block of the 'theme.json' file.
Expected behavior
Static resource should be served properly with no matter where the resource is placed.
Minimal reproducible example
See the test module in Flow flow-tests/test-express-build/test-parent-theme-in-frontend-prod and CSS file
https://github.com/vaadin/flow/blob/281e90b178724846647468c87ee341f557ea53ba/flow-tests/test-express-build/test-parent-theme-in-frontend-prod/frontend/themes/specific-theme/styles.css#L11
Versions
- Vaadin / Flow version: Vaadin 24.1.0.alpha6
Vaadin 24.1 pre uses different approaches for making and adding style tags into head on the page: with pre-compiled dev bundle resolves url in CSS and inlines the resulting CSS into style tag, whereas with pre-compiled prod bundle Flow adds a link tag with the reference VAADIN/themes/my-theme/styles.css. In latter case the image url is resolved into ``VAADIN/themes/my-theme/images/vaadin-logo.png`, which point to nothing.
For pre-compiled prod bundle we need to inline CSS similarly or rewrite the urls. This workaround below leads to proper resource handling:
@Component
public class ApplicationServiceInitListener
implements VaadinServiceInitListener {
@Override
public void serviceInit(ServiceInitEvent event) {
event.addIndexHtmlRequestListener(response -> {
Document document = response.getDocument();
Element head = document.head();
Element styleTag = new Element("style");
styleTag.attr("workaround", "workaround");
// inline CSS
styleTag.appendText("""
.vaadin-logo {
background-image: url("./images/vaadin-logo.png");
}
""");
head.appendChild(styleTag);
});
}
}
Thanks! I think this kind of use-case (linking a static resource from a theme CSS file) isn't supported: the documentation doesn't explicitly mention this use-case: https://vaadin.com/docs/latest/styling/application-theme#images-fonts . Also not mentioned in https://vaadin.com/docs/latest/advanced/loading-resources#flow.resource-cheat-sheet .
You can try background-image: url("/images/vaadin-logo.png"); but that will probably stop working when the app is published under a context root; background-image: url("images/vaadin-logo.png"); also compiles but fails to work in production mode since Vaadin will modify the path to VAADIN/build/images/vaadin-logo.png.
Maybe you could try to lazy-load stylesheet instead of placing it into the theme folder: https://vaadin.com/docs/latest/styling/advanced/lazy-loading-stylesheets . But this kind of solution feels really hacky.
Probably the best workaround at the moment is to move all static resources into frontend/theme folder along the CSS files. But maybe Vaadin could support this kind of linking, e.g. via using context:///images/vaadin-logo.png or similar approach.