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 {