diff --git a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt
index 75e6420d242..1fbab3f05af 100644
--- a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt
+++ b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt
@@ -510,7 +510,7 @@ public class PluginEffectiveConfiguration(
"alwaysExecutePrepareFrontend=${alwaysExecutePrepareFrontend.get()}, " +
"frontendHotdeploy=${frontendHotdeploy.get()}," +
"reactEnable=${reactEnable.get()}," +
- "cleanFrontendFiles=${cleanFrontendFiles.get()}" +
+ "cleanFrontendFiles=${cleanFrontendFiles.get()}," +
"frontendExtraFileExtensions=${frontendExtraFileExtensions.get()}" +
")"
public companion object {
diff --git a/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java b/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java
index b379805621f..8f806af91ec 100644
--- a/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java
+++ b/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java
@@ -238,14 +238,13 @@ public abstract class FlowModeAbstractMojo extends AbstractMojo
/**
* Parameter for adding file extensions to handle during frontend tasks.
*
- * From the commandline use space separated list
- * {@code -DfrontendExtraFileExtensions="svg ico"}
+ * From the commandline use comma separated list
+ * {@code -Ddevmode.frontendExtraFileExtensions="svg,ico"}
*
- *
- * In plugin configuration
+ * In plugin configuration use comma separated values
*
- * svg
- * ico
+ *
+ * svg,ico
*
*
*/
diff --git a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java
index 94f0b6b3236..c82860907c3 100644
--- a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java
+++ b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java
@@ -33,6 +33,7 @@
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
+import java.util.stream.Collectors;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@@ -74,6 +75,7 @@
import static com.vaadin.flow.server.Constants.NPM_TOKEN;
import static com.vaadin.flow.server.Constants.PROJECT_FRONTEND_GENERATED_DIR_TOKEN;
import static com.vaadin.flow.server.InitParameters.APPLICATION_IDENTIFIER;
+import static com.vaadin.flow.server.InitParameters.FRONTEND_EXTRA_EXTENSIONS;
import static com.vaadin.flow.server.InitParameters.FRONTEND_HOTDEPLOY;
import static com.vaadin.flow.server.InitParameters.NODE_DOWNLOAD_ROOT;
import static com.vaadin.flow.server.InitParameters.NODE_VERSION;
@@ -166,7 +168,7 @@ public static void prepareFrontend(PluginAdapterBase adapter)
.withHomeNodeExecRequired(adapter.requireHomeNodeExec())
.setJavaResourceFolder(adapter.javaResourceFolder())
.withProductionMode(false).withReact(adapter.isReactEnabled())
- .withExtraFrontendFileExtensions(
+ .withFrontendExtraFileExtensions(
adapter.frontendExtraFileExtensions());
// Copy jar artifact contents in TaskCopyFrontendFiles
@@ -266,6 +268,12 @@ public static File propagateBuildInfo(PluginAdapterBase adapter) {
buildInfo.put(REACT_ENABLE, adapter.isReactEnabled());
+ if (!adapter.frontendExtraFileExtensions().isEmpty()) {
+ buildInfo.put(FRONTEND_EXTRA_EXTENSIONS,
+ adapter.frontendExtraFileExtensions().stream()
+ .collect(Collectors.joining(",")));
+ }
+
try {
FileUtils.forceMkdir(token.getParentFile());
FileIOUtils.writeIfChanged(token,
@@ -408,7 +416,7 @@ public static void runDevBuildNodeUpdater(PluginAdapterBuild adapter)
.skipDevBundleBuild(adapter.skipDevBundleBuild())
.withCompressBundle(adapter.compressBundle())
.withReact(adapter.isReactEnabled())
- .withExtraFrontendFileExtensions(
+ .withFrontendExtraFileExtensions(
adapter.frontendExtraFileExtensions());
new NodeTasks(options).execute();
} catch (ExecutionFailedException exception) {
@@ -743,6 +751,7 @@ public static void updateBuildFile(PluginAdapterBuild adapter,
buildInfo.remove(NODE_DOWNLOAD_ROOT);
buildInfo.remove(FRONTEND_TOKEN);
buildInfo.remove(FRONTEND_HOTDEPLOY);
+ buildInfo.remove(FRONTEND_EXTRA_EXTENSIONS);
buildInfo.remove(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM);
buildInfo.remove(InitParameters.SERVLET_PARAMETER_ENABLE_BUN);
buildInfo.remove(InitParameters.CI_BUILD);
diff --git a/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java b/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java
index be19d6435c2..391291bb7a0 100644
--- a/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java
+++ b/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java
@@ -179,6 +179,12 @@ public class InitParameters implements Serializable {
*/
public static final String APPLICATION_PARAMETER_DEVMODE_ENABLE_COMPONENT_TRACKER = "devmode.componentTracker.enabled";
+ /**
+ * Configuration parameter name for adding extra file extensions for stats
+ * bundle to generate hashes for.
+ */
+ public static final String FRONTEND_EXTRA_EXTENSIONS = "devmode.frontendExtraFileExtensions";
+
/**
* I18N provider property.
*/
@@ -285,5 +291,4 @@ public class InitParameters implements Serializable {
*/
public static final String APPLICATION_IDENTIFIER = "applicationIdentifier";
- public static final String FRONTEND_EXTRA_EXTENSIONS = "frontendExtraFileExtensions";
}
diff --git a/flow-server/src/main/java/com/vaadin/flow/server/frontend/Options.java b/flow-server/src/main/java/com/vaadin/flow/server/frontend/Options.java
index c4b25be2761..8b55d72e62d 100644
--- a/flow-server/src/main/java/com/vaadin/flow/server/frontend/Options.java
+++ b/flow-server/src/main/java/com/vaadin/flow/server/frontend/Options.java
@@ -4,6 +4,7 @@
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -977,7 +978,7 @@ public boolean isCleanOldGeneratedFiles() {
* the file extensions to add for the project
* @return this builder
*/
- public Options withExtraFrontendFileExtensions(
+ public Options withFrontendExtraFileExtensions(
List frontendExtraFileExtensions) {
this.frontendExtraFileExtensions = frontendExtraFileExtensions;
return this;
diff --git a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateVite.java b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateVite.java
index 6f45170ac74..6703ca93681 100644
--- a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateVite.java
+++ b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateVite.java
@@ -23,6 +23,7 @@
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -121,6 +122,8 @@ private void createGeneratedConfig() throws IOException {
.getResource(FrontendUtils.VITE_GENERATED_CONFIG);
String template = IOUtils.toString(resource, StandardCharsets.UTF_8);
+ System.out.println(
+ "=== '" + options.getFrontendExtraFileExtensions() + "'");
template = template
.replace("#settingsImport#",
"./" + options.getBuildDirectoryName() + "/"
@@ -131,12 +134,8 @@ private void createGeneratedConfig() throws IOException {
webComponentTags == null || webComponentTags.isEmpty()
? ""
: String.join(";", webComponentTags))
- .replace("#frontendExtraFileExtensions#", Optional
- .ofNullable(options.getFrontendExtraFileExtensions())
- .orElse(Collections.emptyList()).stream()
- .map(ext -> ext.replace("'", "\\'"))
- .map(ext -> ext.startsWith(".") ? ext : "." + ext)
- .collect(Collectors.joining("', '", ", '", "'")));
+ .replace("#frontendExtraFileExtensions#",
+ getFrontendExtraFileExtensions());
template = updateFileSystemRouterVitePlugin(template);
FileIOUtils.writeIfChanged(generatedConfigFile, template);
@@ -144,6 +143,19 @@ private void createGeneratedConfig() throws IOException {
generatedConfigFile);
}
+ private String getFrontendExtraFileExtensions() {
+ Optional> frontendExtraFileExtensions = Optional
+ .ofNullable(options.getFrontendExtraFileExtensions());
+ if (frontendExtraFileExtensions.isPresent()
+ && frontendExtraFileExtensions.get().size() > 0) {
+ return frontendExtraFileExtensions.get().stream()
+ .map(ext -> ext.replace("'", "\\'"))
+ .map(ext -> ext.startsWith(".") ? ext : "." + ext)
+ .collect(Collectors.joining("', '", ", '", "'"));
+ }
+ return "";
+ }
+
private String updateFileSystemRouterVitePlugin(String template) {
if (options.isReactEnabled() && FrontendUtils.isHillaUsed(
options.getFrontendDirectory(), options.getClassFinder())) {
diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java
index 5063bbbc1d9..cced90c38f7 100644
--- a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java
+++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java
@@ -187,6 +187,11 @@ protected Map getConfigParametersUsingTokenData(
String.valueOf(buildInfo.getBoolean(PREMIUM_FEATURES)));
}
+ if (buildInfo.hasKey(InitParameters.FRONTEND_EXTRA_EXTENSIONS)) {
+ params.put(InitParameters.FRONTEND_EXTRA_EXTENSIONS, buildInfo
+ .getString(InitParameters.FRONTEND_EXTRA_EXTENSIONS));
+ }
+
setDevModePropertiesUsingTokenData(params, buildInfo);
return params;
}
diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java
index 62e1bdb1913..c9fd429591e 100644
--- a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java
+++ b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java
@@ -350,7 +350,8 @@ public void createInitParameters_valuesAreTakenFromservletConfigAndTokenFile_val
InitParameters.COMPILED_WEB_COMPONENTS_PATH,
InitParameters.NODE_VERSION, InitParameters.NODE_DOWNLOAD_ROOT,
InitParameters.BUILD_FOLDER,
- InitParameters.APPLICATION_IDENTIFIER));
+ InitParameters.APPLICATION_IDENTIFIER,
+ InitParameters.FRONTEND_EXTRA_EXTENSIONS));
Field[] initParamFields = InitParameters.class.getDeclaredFields();
String mockTokenJsonString = generateJsonStringFromFields(
initParamFields, stringParams);
diff --git a/flow-server/src/test/java/com/vaadin/flow/server/frontend/TaskUpdateViteTest.java b/flow-server/src/test/java/com/vaadin/flow/server/frontend/TaskUpdateViteTest.java
index 38ba59203f0..f78241aff8e 100644
--- a/flow-server/src/test/java/com/vaadin/flow/server/frontend/TaskUpdateViteTest.java
+++ b/flow-server/src/test/java/com/vaadin/flow/server/frontend/TaskUpdateViteTest.java
@@ -179,7 +179,7 @@ public void generatedTemplate_reactDisabled_correctFileRouterImport()
@Test
public void generatedTemplate_extraFrontendExtension_addedToViteConfiguration()
throws IOException {
- options.withExtraFrontendFileExtensions(
+ options.withFrontendExtraFileExtensions(
Arrays.asList(".svg", ".ico", "png"));
TaskUpdateVite task = new TaskUpdateVite(options, null);
task.execute();
@@ -198,4 +198,25 @@ public void generatedTemplate_extraFrontendExtension_addedToViteConfiguration()
"'.js', '.js.map', '.ts', '.ts.map', '.tsx', '.tsx.map', '.css', '.css.map', '.svg', '.ico', '.png'",
matcher.group(1));
}
+
+ @Test
+ public void generatedTemplate_noEraFrontendExtension_viteConfigurationWithoutExtraSelections()
+ throws IOException {
+ TaskUpdateVite task = new TaskUpdateVite(options, null);
+ task.execute();
+
+ File configFile = new File(temporaryFolder.getRoot(),
+ FrontendUtils.VITE_GENERATED_CONFIG);
+
+ String template = IOUtils.toString(configFile.toURI(),
+ StandardCharsets.UTF_8);
+ Pattern matchSelection = Pattern
+ .compile("const projectFileExtensions = \\[(.*)];");
+ Matcher matcher = matchSelection.matcher(template);
+ Assert.assertTrue("No projectFileExtensions found", matcher.find());
+ Assert.assertEquals(
+ "Extra frontend extensions should be added to vite configuration, but was not.",
+ "'.js', '.js.map', '.ts', '.ts.map', '.tsx', '.tsx.map', '.css', '.css.map'",
+ matcher.group(1));
+ }
}
diff --git a/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/pom.xml b/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/pom.xml
index b5edddbdbed..4ef597ebb9d 100644
--- a/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/pom.xml
+++ b/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/pom.xml
@@ -111,6 +111,9 @@
+
+ scss
+
maven-clean-plugin
diff --git a/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/main/frontend/styles/my-sass.scss b/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/main/frontend/styles/my-sass.scss
new file mode 100644
index 00000000000..b07e52815e5
--- /dev/null
+++ b/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/main/frontend/styles/my-sass.scss
@@ -0,0 +1,3 @@
+p {
+ border: 3px solid orange;
+}
diff --git a/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/main/java/com/vaadin/flow/frontend/DevBundleCssImportView.java b/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/main/java/com/vaadin/flow/frontend/DevBundleCssImportView.java
index 8b26a4018ab..fe4a4c96812 100644
--- a/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/main/java/com/vaadin/flow/frontend/DevBundleCssImportView.java
+++ b/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/main/java/com/vaadin/flow/frontend/DevBundleCssImportView.java
@@ -16,12 +16,15 @@
package com.vaadin.flow.frontend;
import com.vaadin.flow.component.dependency.CssImport;
+import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.router.Route;
@Route("com.vaadin.flow.frontend.DevBundleCssImportView")
@CssImport("./styles/my-styles.css")
+@CssImport("./styles/my-sass.scss")
+@NpmPackage(value = "sass-embedded", version = "1.80.6")
public class DevBundleCssImportView extends Div {
static final String MY_COMPONENT_ID = "test-css-import-meta-inf-resources-span";
diff --git a/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/test/java/com/vaadin/flow/frontend/DevBundleCssImportIT.java b/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/test/java/com/vaadin/flow/frontend/DevBundleCssImportIT.java
index 831a6b9894d..769d0167791 100644
--- a/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/test/java/com/vaadin/flow/frontend/DevBundleCssImportIT.java
+++ b/flow-tests/test-express-build/test-dev-bundle-frontend-add-on/src/test/java/com/vaadin/flow/frontend/DevBundleCssImportIT.java
@@ -59,7 +59,22 @@ public void cssImportedStyles_hashCalculatedWithNotQuestionMark()
found = true;
}
}
- Assert.assertTrue("My-styles.css import is expected", found);
+
+ Assert.assertTrue("my-sass.scss content hash is expected",
+ frontendHashes.hasKey("styles/my-sass.scss"));
+ Assert.assertEquals("Unexpected my-sass.scss content hash",
+ "719cbd39e90caeecd2290124044e7cefb9e6150d3c338d4df71c21bcad825ab5",
+ frontendHashes.getString("styles/my-sass.scss"));
+
+ Assert.assertTrue("my-sass.scss import is expected", found);
+ found = false;
+ for (int i = 0; i < bundleImports.length(); i++) {
+ if (bundleImports.get(i).asString()
+ .equals("Frontend/styles/my-sass.scss")) {
+ found = true;
+ }
+ }
+ Assert.assertTrue("my-sass.scss import is expected", found);
}
@Test
diff --git a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java
index 67b2bc729b9..4477e32895f 100644
--- a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java
+++ b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java
@@ -265,11 +265,11 @@ public static DevModeHandler initDevModeHandler(Set> classes,
File frontendGeneratedFolder = new File(frontendGeneratedFolderName);
File jarFrontendResourcesFolder = new File(frontendGeneratedFolder,
FrontendUtils.JAR_RESOURCES_FOLDER);
- JsonObject tokenFileData = Json.createObject();
Mode mode = config.getMode();
boolean reactEnable = config.getBooleanProperty(REACT_ENABLE,
FrontendUtils
.isReactRouterRequired(options.getFrontendDirectory()));
+
options.enablePackagesUpdate(true)
.useByteCodeScanner(useByteCodeScanner)
.withFrontendGeneratedFolder(frontendGeneratedFolder)
@@ -279,7 +279,6 @@ public static DevModeHandler initDevModeHandler(Set> classes,
Constants.LOCAL_FRONTEND_RESOURCES_PATH))
.enableImportsUpdate(true)
.withRunNpmInstall(mode == Mode.DEVELOPMENT_FRONTEND_LIVERELOAD)
- .populateTokenFileData(tokenFileData)
.withEmbeddableWebComponents(true).withEnablePnpm(enablePnpm)
.withEnableBun(enableBun).useGlobalPnpm(useGlobalPnpm)
.withHomeNodeExecRequired(useHomeNodeExec)
@@ -289,12 +288,11 @@ public static DevModeHandler initDevModeHandler(Set> classes,
.withFrontendHotdeploy(
mode == Mode.DEVELOPMENT_FRONTEND_LIVERELOAD)
.withBundleBuild(mode == Mode.DEVELOPMENT_BUNDLE)
- .withReact(reactEnable);
-
- NodeTasks tasks = new NodeTasks(options);
+ .withReact(reactEnable).withFrontendExtraFileExtensions(
+ getFrontendExtraFileExtensions(config));
Runnable runnable = () -> {
- runNodeTasks(context, tokenFileData, tasks);
+ runNodeTasks(new NodeTasks(options));
if (mode == Mode.DEVELOPMENT_FRONTEND_LIVERELOAD) {
// For Vite, wait until a VaadinServlet is deployed so we know
// which frontend servlet path to use
@@ -329,6 +327,17 @@ public static DevModeHandler initDevModeHandler(Set> classes,
}
}
+ private static List getFrontendExtraFileExtensions(
+ ApplicationConfiguration config) {
+ List stringProperty = Arrays.asList(config
+ .getStringProperty(InitParameters.FRONTEND_EXTRA_EXTENSIONS, "")
+ .split(","));
+ if (stringProperty.isEmpty()) {
+ return null;
+ }
+ return stringProperty;
+ }
+
private static Logger log() {
return LoggerFactory.getLogger(DevModeStartupListener.class);
}
@@ -350,8 +359,7 @@ static Set getFrontendLocationsFromClassloader(
return frontendFiles;
}
- private static void runNodeTasks(VaadinContext vaadinContext,
- JsonObject tokenFileData, NodeTasks tasks) {
+ private static void runNodeTasks(NodeTasks tasks) {
try {
tasks.execute();
} catch (ExecutionFailedException exception) {