diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java b/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java
index 9906caf1f92..cb2f80e5133 100644
--- a/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java
+++ b/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java
@@ -15,17 +15,9 @@
*/
package com.vaadin.flow.server;
-import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_WEBPACK_ERROR_PATTERN;
-import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_WEBPACK_OPTIONS;
-import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_WEBPACK_SUCCESS_PATTERN;
-import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_WEBPACK_TIMEOUT;
-import static com.vaadin.flow.server.frontend.FrontendUtils.GREEN;
-import static com.vaadin.flow.server.frontend.FrontendUtils.RED;
-import static com.vaadin.flow.server.frontend.FrontendUtils.YELLOW;
-import static com.vaadin.flow.server.frontend.FrontendUtils.commandToString;
-import static com.vaadin.flow.server.frontend.FrontendUtils.console;
-import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
-import static java.net.HttpURLConnection.HTTP_OK;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.File;
@@ -44,15 +36,13 @@
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.regex.Pattern;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
@@ -65,6 +55,18 @@
import com.vaadin.flow.server.frontend.FrontendTools;
import com.vaadin.flow.server.frontend.FrontendUtils;
+import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_WEBPACK_ERROR_PATTERN;
+import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_WEBPACK_OPTIONS;
+import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_WEBPACK_SUCCESS_PATTERN;
+import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_WEBPACK_TIMEOUT;
+import static com.vaadin.flow.server.frontend.FrontendUtils.GREEN;
+import static com.vaadin.flow.server.frontend.FrontendUtils.RED;
+import static com.vaadin.flow.server.frontend.FrontendUtils.YELLOW;
+import static com.vaadin.flow.server.frontend.FrontendUtils.commandToString;
+import static com.vaadin.flow.server.frontend.FrontendUtils.console;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_OK;
+
/**
* Handles getting resources from webpack-dev-server
.
*
@@ -134,12 +136,23 @@ private DevModeHandler(DeploymentConfiguration config, int runningPort,
port = runningPort;
reuseDevServer = config.reuseDevServer();
- devServerStartFuture = waitFor.whenCompleteAsync((value, exception) -> {
+ // Check whether executor is provided by the caller (framework)
+ Object service = config.getInitParameters().get(Executor.class);
+
+ BiConsumer action = (value, exception) -> {
// this will throw an exception if an exception has been thrown by
// the waitFor task
waitFor.getNow(null);
runOnFutureComplete(config);
- });
+ };
+
+ if (service instanceof Executor) {
+ // if there is an executor use it to run the task
+ devServerStartFuture = waitFor.whenCompleteAsync(action,
+ (Executor) service);
+ } else {
+ devServerStartFuture = waitFor.whenCompleteAsync(action);
+ }
}
/**
@@ -648,8 +661,10 @@ private boolean doStartWebpack(DeploymentConfiguration config,
getLogger().info(LOG_END, ms);
saveRunningDevServerPort();
return true;
- } catch (IOException | InterruptedException e) {
+ } catch (IOException e) {
getLogger().error("Failed to start the webpack process", e);
+ } catch (InterruptedException e) {
+ getLogger().debug("Webpack process start has been interrupted", e);
}
return false;
}
diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java
index 1c4ca16bbf6..e0c1d227423 100644
--- a/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java
+++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java
@@ -45,6 +45,7 @@
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
+import java.util.concurrent.Executor;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -320,8 +321,8 @@ public static void initDevModeHandler(Set> classes,
.enableImportsUpdate(true).runNpmInstall(true)
.populateTokenFileData(tokenFileData)
.withEmbeddableWebComponents(true).enablePnpm(enablePnpm)
- .withHomeNodeExecRequired(useHomeNodeExec)
- .build().execute();
+ .withHomeNodeExecRequired(useHomeNodeExec).build()
+ .execute();
FallbackChunk chunk = FrontendUtils
.readFallbackChunk(tokenFileData);
@@ -345,25 +346,23 @@ public static void initDevModeHandler(Set> classes,
.withEmbeddableWebComponents(true).enablePnpm(enablePnpm)
.withHomeNodeExecRequired(useHomeNodeExec).build();
- CompletableFuture runNodeTasks = CompletableFuture
- .runAsync(() -> {
- try {
- tasks.execute();
-
- FallbackChunk chunk = FrontendUtils
- .readFallbackChunk(tokenFileData);
- if (chunk != null) {
- vaadinContext.setAttribute(chunk);
- }
- } catch (ExecutionFailedException exception) {
- log().debug(
- "Could not initialize dev mode handler. One of the node tasks failed",
- exception);
- throw new CompletionException(exception);
- }
- });
-
- DevModeHandler.start(config, builder.npmFolder, runNodeTasks);
+ // Check whether executor is provided by the caller (framework)
+ Object service = config.getInitParameters().get(Executor.class);
+
+ Runnable runnable = () -> runNodeTasks(vaadinContext, tokenFileData,
+ tasks);
+
+ CompletableFuture nodeTasksFuture;
+ if (service instanceof Executor) {
+ // if there is an executor use it to run the task
+ nodeTasksFuture = CompletableFuture.runAsync(runnable,
+ (Executor) service);
+ } else {
+ nodeTasksFuture = CompletableFuture.runAsync(runnable);
+
+ }
+
+ DevModeHandler.start(config, builder.npmFolder, nodeTasksFuture);
}
private static Logger log() {
@@ -422,6 +421,24 @@ static Set getFrontendLocationsFromClassloader(
return frontendFiles;
}
+ private static void runNodeTasks(VaadinContext vaadinContext,
+ JsonObject tokenFileData, NodeTasks tasks) {
+ try {
+ tasks.execute();
+
+ FallbackChunk chunk = FrontendUtils
+ .readFallbackChunk(tokenFileData);
+ if (chunk != null) {
+ vaadinContext.setAttribute(chunk);
+ }
+ } catch (ExecutionFailedException exception) {
+ log().debug(
+ "Could not initialize dev mode handler. One of the node tasks failed",
+ exception);
+ throw new CompletionException(exception);
+ }
+ }
+
private static Set getFrontendLocationsFromClassloader(
ClassLoader classLoader, String resourcesFolder)
throws ServletException {