From fb4f2b3d9faefe096a8562d89e8d88ce1d9efaff Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 12 Jun 2026 20:03:22 +0300 Subject: [PATCH] docs: document META-INF/frontend as the correct location for add-on frontend files META-INF/resources/frontend is deprecated: everything under META-INF/resources is also published as static resources, so the un-bundled source files are served directly to browsers. Also clarify that add-on CSS typically goes in META-INF/resources and is loaded with @StyleSheet; @CssImport with META-INF/frontend is only for CSS that should be included in the frontend bundle. --- .../project-structure/multi-module.adoc | 2 +- .../components/package-component.adoc | 35 ++++++++++++------- .../components/style-component.adoc | 2 +- articles/components/map/index.adoc | 2 +- articles/flow/advanced/loading-resources.adoc | 10 ++++-- articles/flow/configuration/properties.adoc | 2 +- 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/articles/building-apps/architecture/project-structure/multi-module.adoc b/articles/building-apps/architecture/project-structure/multi-module.adoc index 9eace2c710..835c97c71f 100644 --- a/articles/building-apps/architecture/project-structure/multi-module.adoc +++ b/articles/building-apps/architecture/project-structure/multi-module.adoc @@ -343,7 +343,7 @@ Store frontend sources, such as CSS files and JavaScript, in the `src/main/front === Multiple UI Modules -If you are using *package by feature*, you'll have more than one UI module. In this case, you should treat the UI modules as Vaadin *add-ons*. This means you have to store module-specific CSS files, JavaScript, and images in the `src/main/resources/META-INF/resources` directory. See <> for more information. +If you are using *package by feature*, you'll have more than one UI module. In this case, you should treat the UI modules as Vaadin *add-ons*. This means you have to store module-specific CSS files and static resources, such as images, in the `src/main/resources/META-INF/resources` directory, and JavaScript modules in the `src/main/resources/META-INF/frontend` directory. See <> for more information. Add the theme files and the Vaadin Maven plugin to the _application module_, which is covered in the next section. diff --git a/articles/building-apps/components/package-component.adoc b/articles/building-apps/components/package-component.adoc index fcc75d5ef9..cba0e24085 100644 --- a/articles/building-apps/components/package-component.adoc +++ b/articles/building-apps/components/package-component.adoc @@ -44,8 +44,7 @@ my-component/ │ │ │ └── TheAddon.java │ │ └── resources/ │ │ └── META-INF/ -│ │ └── resources/ -│ │ └── frontend/ +│ │ └── frontend/ │ └── test/ │ └── java/ │ └── org/vaadin/addons/mygroup/ @@ -85,41 +84,53 @@ The starter includes a `directory` Maven profile that builds a ZIP file for the == Frontend Resources -If your add-on includes CSS, JavaScript, or TypeScript files, place them under: +If your add-on includes JavaScript or TypeScript modules, or CSS files that should be included in the frontend bundle, place them under: ---- -src/main/resources/META-INF/resources/frontend/ +src/main/resources/META-INF/frontend/ ---- -Files in this location are automatically discovered by Vaadin when the add-on JAR is on the classpath. Reference them from your Java component with `@JsModule` or `@CssImport`: +Files in this location are automatically discovered by Vaadin when the add-on JAR is on the classpath, and are processed by the Vite build pipeline. Reference them from your Java component with `@JsModule` or `@CssImport`: [source,java] ---- -@CssImport("./my-component/status-badge.css") +@JsModule("./my-component/status-badge.js") public class StatusBadge extends Composite { // ... } ---- -The `./` prefix maps to the `frontend/` directory on the classpath, which includes your `META-INF/resources/frontend/` files. +The `./` prefix maps to the `frontend/` directory on the classpath, which includes your `META-INF/frontend/` files. -Add-ons use `@CssImport` rather than `@StyleSheet` because their frontend resources are placed in `META-INF/resources/frontend/`, which is processed by the Vite build pipeline. `@StyleSheet` resolves against the static resources root, `META-INF/resources/`, and is the standard approach for application code — see <>. +During development, you can also use `src/main/frontend/` for convenience — Vaadin picks up files from there as well. However, only files in `META-INF/frontend/` are included in the published JAR. -During development, you can also use `src/main/frontend/` for convenience — Vaadin picks up files from there as well. However, only files in `META-INF/resources/frontend/` are included in the published JAR. +[NOTE] +.Deprecated Location +Some earlier add-ons place frontend files in `src/main/resources/META-INF/resources/frontend/` instead. That location still works, but it's deprecated: everything under `META-INF/resources/` is also published as static resources, so the un-bundled source files are served directly to browsers — which is usually not what you want. Use `META-INF/frontend/` so the files are only used as input for the frontend bundle. == Including Stylesheets -For components that need CSS, you have two options: +CSS files typically go in the static resources folder, `src/main/resources/META-INF/resources/`, and are loaded with `@StyleSheet` — the same approach as in application code (see <>): + +[source,java] +---- +@StyleSheet("my-component/status-badge.css") +public class StatusBadge extends Composite { + // ... +} +---- + +The path resolves against the static resources root, so the example above loads `src/main/resources/META-INF/resources/my-component/status-badge.css`. -*Application-scoped CSS* — use `@CssImport` to load a stylesheet into the application: +If you want the CSS to be included in the frontend bundle instead of served as a separate file, place it in `META-INF/frontend/` and load it with `@CssImport`: [source,java] ---- @CssImport("./my-component/status-badge.css") ---- -*Component-scoped CSS for Vaadin components* — to inject styles into a Vaadin component's shadow DOM, use the `themeFor` attribute: +`@CssImport` is also needed to inject styles into a Vaadin component's shadow DOM, using the `themeFor` attribute: [source,java] ---- diff --git a/articles/building-apps/components/style-component.adoc b/articles/building-apps/components/style-component.adoc index 016713a424..2f52b46c00 100644 --- a/articles/building-apps/components/style-component.adoc +++ b/articles/building-apps/components/style-component.adoc @@ -125,7 +125,7 @@ The lazy approach is useful for components with significant CSS that isn't neede [NOTE] .Add-On JAR Packaging -If you're packaging the component as a reusable add-on JAR, CSS files go in `META-INF/resources/frontend/` and are loaded with `@CssImport` instead. See <> for details. +If you're packaging the component as a reusable add-on JAR, use the `@StyleSheet` approach — the consuming application's `styles.css` isn't available to the add-on, so you can't import from it. See <> for details. === Use Theme Custom Properties diff --git a/articles/components/map/index.adoc b/articles/components/map/index.adoc index 3651871d3e..22eaf861a1 100644 --- a/articles/components/map/index.adoc +++ b/articles/components/map/index.adoc @@ -385,7 +385,7 @@ import com.vaadin.flow.server.streams.DownloadHandler; // Assuming the given image is in the JAR resources DownloadHandler downloadHandler = DownloadHandler.forClassResource( - getClass(), "/META-INF/resources/frontend/custom-cluster.png", + getClass(), "/images/custom-cluster.png", "custom-cluster.png").inline(); Icon.Options iconOptions = new Icon.Options(); iconOptions.setImg(downloadHandler); diff --git a/articles/flow/advanced/loading-resources.adoc b/articles/flow/advanced/loading-resources.adoc index f9a6db297f..0ea84e1d59 100644 --- a/articles/flow/advanced/loading-resources.adoc +++ b/articles/flow/advanced/loading-resources.adoc @@ -69,12 +69,16 @@ The following tables show how to load various resources and where the resource f |File type |Import |File location |CSS files +|`@StyleSheet("my-styles/styles.css")`<> +|`/src/main/resources/META-INF/resources/my-styles/styles.css` + +|CSS files included in the frontend bundle |`@CssImport("./my-styles/styles.css")`<> -|`/src/main/resources/META-INF/resources/frontend/my-styles/styles.css` +|`/src/main/resources/META-INF/frontend/my-styles/styles.css`<> |JavaScript, TypeScript and Lit templates |`@JsModule("./src/my-script.js")`<> -|`/src/main/resources/META-INF/resources/frontend/src/my-script.js` +|`/src/main/resources/META-INF/frontend/src/my-script.js`<> |Static files, such as images and icons (for example, the favicon) |`new Image("img/flower.jpg", "A flower")` @@ -101,6 +105,8 @@ Anchor anchor = new Anchor("assets/document.pdf", "A document"); anchor.getElement().setAttribute("router-ignore", true); ---- +. [[foot-3]]Some earlier add-ons use the `/src/main/resources/META-INF/resources/frontend` folder instead. That location still works, but it's deprecated: everything under `META-INF/resources` is also published as static resources, so the un-bundled source files are served directly to browsers. + == Programmatically Load Resources diff --git a/articles/flow/configuration/properties.adoc b/articles/flow/configuration/properties.adoc index 4d69bc2028..1a312de670 100644 --- a/articles/flow/configuration/properties.adoc +++ b/articles/flow/configuration/properties.adoc @@ -228,7 +228,7 @@ Default: `false` + Mode: Development `**frontend.hotdeploy.dependencies**`:: -A comma-separated list of module directories to watch for frontend file changes when detecting hot-deployable resources. Entries need to point to directories relative to the module that starts the Vaadin application, and can point to the module itself as well, in case it provides frontend files as resources. The value could be for example "./,./component-module-1,./component-module-2". Flow will watch for changes in both `src/main/resources/META-INF/resources/frontend` and the legacy `src/main/resources/META-INF/frontend` directories under the given three directory entries. Do note that if this parameter is not defined, Vaadin watches for changes under `src/main/resources/META-INF/` in the module that starts the Vaadin application, but when you provide a custom value for the parameter you need to add "./" to the list of directories to watch for the same effect. + +A comma-separated list of module directories to watch for frontend file changes when detecting hot-deployable resources. Entries need to point to directories relative to the module that starts the Vaadin application, and can point to the module itself as well, in case it provides frontend files as resources. The value could be for example "./,./component-module-1,./component-module-2". Flow will watch for changes in both `src/main/resources/META-INF/frontend` and the deprecated `src/main/resources/META-INF/resources/frontend` directories under the given three directory entries. Do note that if this parameter is not defined, Vaadin watches for changes under `src/main/resources/META-INF/` in the module that starts the Vaadin application, but when you provide a custom value for the parameter you need to add "./" to the list of directories to watch for the same effect. + Default: `""` + Mode: Development