Skip to content

Commit

Permalink
Add liveReload.enabled config parameter to enable/disable Live Reload (
Browse files Browse the repository at this point in the history
…#7884)

* Add devmode.liveReload.enabled config parameter to enable/disable Live Reload
Fix #7874
* Disable live reload in all IT modules except test-dev-mode
  • Loading branch information
mehdi-vaadin authored Mar 30, 2020
1 parent d863953 commit 93f0a40
Show file tree
Hide file tree
Showing 23 changed files with 342 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class ApplicationConfiguration {
private boolean productionMode;
private boolean requestTiming;
private boolean webComponentMode;
private boolean devModeLiveReloadEnabled;

private String servletVersion;
private String atmosphereVersion;
Expand Down Expand Up @@ -333,4 +334,24 @@ public void setExportedWebComponents(String[] exportedWebComponents) {
public String[] getExportedWebComponents() {
return exportedWebComponents;
}

/**
* Checks if dev mode live reload is enabled or not.
*
* @return {@code true} if dev mode live reload is enabled, {@code false} otherwise
*/
public boolean isDevModeLiveReloadEnabled() {
return devModeLiveReloadEnabled;
}

/**
* Sets whether dev mode live reload should be enabled or not.
*
* @param devModeLiveReloadEnabled
* {@code true} if dev mode live reload should be enabled, {@code false}
* otherwise
*/
public void setDevModeLiveReloadEnabled(boolean devModeLiveReloadEnabled) {
this.devModeLiveReloadEnabled = devModeLiveReloadEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,11 @@ public ApplicationConnection(
servletVersion);
Console.log(
"Vaadin application servlet version: " + servletVersion);
// registry.getLiveReload().show(
// applicationConfiguration.getServiceUrl(),
// applicationConfiguration.getUIId());
if (applicationConfiguration.isDevModeLiveReloadEnabled()) {
registry.getLiveReload().show(
applicationConfiguration.getServiceUrl(),
applicationConfiguration.getUIId());
}
}

registry.getLoadingIndicator().show();
Expand Down
24 changes: 12 additions & 12 deletions flow-client/src/main/java/com/vaadin/client/LiveReload.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@
import elemental.json.JsonObject;

/**
* Responsible for the client-side of the Live Reload. It refreshes the page
* when it receives a reload command from Loive Reload server (either Spring or
* Responsible for the client-side of the live reload. It refreshes the page
* when it receives a reload command from live-reload server (either Spring or
* Flow).
*
* @author Vaadin Ltd
* @since
*/
public class LiveReload {
// The default value is true meaning if the key doesn't exist in the local
// storage Live Reload is enabled.
// storage live reload is enabled.
private static final String ENABLED_KEY_IN_STORAGE = "vaadin.live-reload.enabled";
private static final String ACTIVE_KEY_IN_SESSION_STORAGE = "vaadin.live-reload.active";
private static final int SPRING_DEV_TOOLS_PORT = 35729;
Expand All @@ -44,20 +44,20 @@ public class LiveReload {
private Element indicator;

/**
* Connects to either Spring Dev Tools Live Reload server or Flow Live
* Connects to either Spring Dev Tools live-reload server or Flow Live
* Reload server and if the connection is successful shows an overlay on the
* page including the status of the Live Reload.
* page including the status of the live reload.
*
* @param serviceUrl
* The root URL of the application that should be used to connect
* to Flow Live Reload server
* to Flow live-reload server
* @param uiId
* The UI id
*/
public void show(String serviceUrl, int uiId) {
this.serviceUrl = serviceUrl;
this.uiId = uiId;
if (isEnabled()) {
if (isEnabledOnThisBrowser()) {
indicator = getOrCreateIndicator();
openWebSocketConnection();
}
Expand All @@ -72,7 +72,7 @@ private void openWebSocketConnection() {
webSocket.setOnerror(springWsEvent -> {
if (!serviceUrl.startsWith("http://")) {
Console.debug(
"The protocol of the url should be http for Live Reload to work.");
"The protocol of the url should be http for live reload to work.");
return;
}

Expand Down Expand Up @@ -119,7 +119,7 @@ private void handleMessageEvent(Event evt) {

private void handleErrorEvent(Event ev) {
Console.debug(
"Live Reload server is not available, neither Spring Dev Tools nor the Flow built-in. Live Reload won't work automatically.");
"Live-reload server is not available, neither Spring Dev Tools nor the Flow built-in. Live reload won't work automatically.");
showMessage(
"Live reload: error; check browser console for more details");
}
Expand Down Expand Up @@ -179,7 +179,7 @@ private Element getOrCreateIndicator() {
overlay.appendChild(disableButton);
disableButton.getStyle().setTextDecoration("underline");
disableButton.getStyle().setCursor("pointer");
disableButton.setOnclick(e -> disable());
disableButton.setOnclick(e -> disableOnThisBrowser());

reloadIndicator.appendChild(overlay);
Browser.getDocument().getBody().appendChild(reloadIndicator);
Expand Down Expand Up @@ -227,12 +227,12 @@ private void updateActiveIndicator() {
}
}

private boolean isEnabled() {
private boolean isEnabledOnThisBrowser() {
String enabled = StorageUtil.getLocalItem(ENABLED_KEY_IN_STORAGE);
return enabled == null || Boolean.parseBoolean(enabled);
}

private void disable() {
private void disableOnThisBrowser() {
assert indicator != null;

closeWebSocketConnection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;

import com.vaadin.client.ApplicationConfiguration;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Console;
Expand All @@ -27,6 +26,7 @@
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.flow.collection.JsArray;
import com.vaadin.client.flow.collection.JsCollections;
import com.vaadin.flow.server.Constants;
import com.vaadin.flow.shared.ApplicationConstants;

/**
Expand Down Expand Up @@ -163,6 +163,8 @@ private static void populateApplicationConfiguration(
jsoConfiguration.getConfigBoolean("requestTiming"));
conf.setExportedWebComponents(
jsoConfiguration.getConfigStringArray("webcomponents"));
conf.setDevModeLiveReloadEnabled(jsoConfiguration.getConfigBoolean(
Constants.SERVLET_PARAMETER_DEVMODE_ENABLE_LIVE_RELOAD));
}

private static void doStartApplication(final String applicationId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
import com.vaadin.flow.shared.communication.PushMode;

import static com.vaadin.flow.server.Constants.POLYFILLS_DEFAULT_VALUE;
import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_USE_V14_BOOTSTRAP;
import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_POLYFILLS;
import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_USE_V14_BOOTSTRAP;

/**
* A collection of properties configured at deploy time as well as a way of
Expand Down Expand Up @@ -300,9 +300,10 @@ default String getCompiledWebComponentsPath() {
* @return polyfills to load
*/
default List<String> getPolyfills() {
return Arrays.asList(getStringProperty(SERVLET_PARAMETER_POLYFILLS,
POLYFILLS_DEFAULT_VALUE).split("[, ]+")).stream()
.filter(polyfill -> !polyfill.isEmpty())
return Arrays
.asList(getStringProperty(SERVLET_PARAMETER_POLYFILLS,
POLYFILLS_DEFAULT_VALUE).split("[, ]+"))
.stream().filter(polyfill -> !polyfill.isEmpty())
.collect(Collectors.toList());
}

Expand Down Expand Up @@ -372,6 +373,13 @@ default boolean isEagerServerLoad() {
false);
}

/**
* Checks if dev mode live reload is enabled or not.
*
* @return {@code true} if dev mode live reload is enabled, {@code false} otherwise
*/
boolean isDevModeLiveReloadEnabled();

/**
* Returns whether pnpm is enabled or not.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public interface BrowserLiveReload {
*
* @param resource
* a web socket connection resource, not <code>null</code>.
* @return whether the web socket connection is for live-reload
* @return whether the web socket connection is for live reload
*/
boolean isLiveReload(AtmosphereResource resource);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ public class BrowserLiveReloadAccess {
public BrowserLiveReload getLiveReload(VaadinService service) {
if (service.getDeploymentConfiguration().isProductionMode()) {
LoggerFactory.getLogger(BrowserLiveReloadAccess.class)
.debug("Live reload getter is called in production mode.");
.debug("BrowserLiveReloadAccess::getLiveReload is called in production mode.");
return null;
}
if (!service.getDeploymentConfiguration().isDevModeLiveReloadEnabled()) {
LoggerFactory.getLogger(BrowserLiveReloadAccess.class)
.debug("BrowserLiveReloadAccess::getLiveReload is called when live reload is disabled.");
return null;
}
VaadinContext context = service.getContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
import elemental.json.JsonType;
import elemental.json.JsonValue;
import elemental.json.impl.JsonUtil;

import static com.vaadin.flow.server.Constants.VAADIN_MAPPING;
import static com.vaadin.flow.server.frontend.FrontendUtils.EXPORT_CHUNK;
import static java.nio.charset.StandardCharsets.UTF_8;
Expand Down Expand Up @@ -510,7 +509,8 @@ public Document getBootstrapPage(BootstrapContext context) {
head, initialPageSettings));

if (!config.isProductionMode()) {
UsageStatisticsExporter.exportUsageStatisticsToDocument(document);
UsageStatisticsExporter
.exportUsageStatisticsToDocument(document);
}

setupPwa(document, context);
Expand Down Expand Up @@ -749,19 +749,28 @@ private void appendNpmBundle(Element head, VaadinService service,
BootstrapContext context) throws IOException {
String content = FrontendUtils.getStatsAssetsByChunkName(service);
if (content == null) {
StringBuilder message = new StringBuilder("The stats file from webpack (stats.json) was not found.\n");
if(service.getDeploymentConfiguration().isProductionMode()) {
StringBuilder message = new StringBuilder(
"The stats file from webpack (stats.json) was not found.\n");
if (service.getDeploymentConfiguration().isProductionMode()) {
message.append(
"The application is running in production mode.");
message.append("Verify that build-frontend task has executed successfully and that stats.json is on the classpath.");
message.append("Or switch application to development mode.");
} else if(!service.getDeploymentConfiguration().enableDevServer()) {
message.append("Dev server is disabled for the application.");
message.append("Verify that build-frontend task has executed successfully and that stats.json is on the classpath.");
message.append(
"Verify that build-frontend task has executed successfully and that stats.json is on the classpath.");
message.append(
"Or switch application to development mode.");
} else if (!service.getDeploymentConfiguration()
.enableDevServer()) {
message.append(
"Dev server is disabled for the application.");
message.append(
"Verify that build-frontend task has executed successfully and that stats.json is on the classpath.");
} else {
message.append("This typically mean that you have started the application without executing the 'prepare-frontend' Maven target.\n");
message.append("If you are using Spring Boot and are launching the Application class directly, ");
message.append("you need to run \"mvn install\" once first or launch the application using \"mvn spring-boot:run\"");
message.append(
"This typically mean that you have started the application without executing the 'prepare-frontend' Maven target.\n");
message.append(
"If you are using Spring Boot and are launching the Application class directly, ");
message.append(
"you need to run \"mvn install\" once first or launch the application using \"mvn spring-boot:run\"");
}
throw new IOException(message.toString());
}
Expand Down Expand Up @@ -1069,6 +1078,8 @@ private JsonObject getApplicationParameters(VaadinRequest request,
versionInfo.put("atmosphereVersion", atmosphereVersion);
}
appConfig.put("versionInfo", versionInfo);
appConfig.put(Constants.SERVLET_PARAMETER_DEVMODE_ENABLE_LIVE_RELOAD,
deploymentConfiguration.isDevModeLiveReloadEnabled());
}

// Use locale from session if set, else from the request
Expand Down Expand Up @@ -1101,7 +1112,7 @@ private JsonObject getApplicationParameters(VaadinRequest request,

appConfig.put("heartbeatInterval",
deploymentConfiguration.getHeartbeatInterval());

appConfig.put("maxMessageSuspendTimeout",
deploymentConfiguration.getMaxMessageSuspendTimeout());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ public final class Constants implements Serializable {
*/
public static final String VAADIN_VERSIONS_JSON = "vaadin_versions.json";

/**
* Configuration parameter name for enabling live reload.
*
* @since
*/
public static final String SERVLET_PARAMETER_DEVMODE_ENABLE_LIVE_RELOAD = "devmode.liveReload.enabled";

private Constants() {
// prevent instantiation constants class only
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.vaadin.flow.shared.communication.PushMode;

import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_CLOSE_IDLE_SESSIONS;
import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_DEVMODE_ENABLE_LIVE_RELOAD;
import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION;
import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_PRODUCTION_MODE;
import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_REQUEST_TIMING;
Expand Down Expand Up @@ -205,4 +206,16 @@ public Properties getInitParameters() {
return initParameters;
}

/**
* Checks if dev mode live reload is enabled or not. It is always disabled
* in production mode. In development mode, it is enabled by default.
*
* @return {@code true} if dev mode live reload is enabled, {@code false}
* otherwise
*/
@Override
public boolean isDevModeLiveReloadEnabled() {
return !isProductionMode() && getBooleanProperty(
SERVLET_PARAMETER_DEVMODE_ENABLE_LIVE_RELOAD, true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,10 @@ void connectionLost(AtmosphereResourceEvent event) {
return;
}

// In development mode we may have a live-reload push channel
// that should be closed.
// In development mode we may have a live-reload push channel
// that should be closed.

if (!service.getDeploymentConfiguration().isProductionMode()) {
if (service.getDeploymentConfiguration().isDevModeLiveReloadEnabled()) {
BrowserLiveReloadAccess access = service.getInstantiator()
.getOrCreate(BrowserLiveReloadAccess.class);
BrowserLiveReload liveReload = access.getLiveReload(service);
Expand Down Expand Up @@ -484,7 +484,7 @@ private static boolean isPushIdValid(VaadinSession session,
void onConnect(AtmosphereResource resource) {
String refreshConnection = resource.getRequest()
.getParameter(ApplicationConstants.LIVE_RELOAD_CONNECTION);
if (!service.getDeploymentConfiguration().isProductionMode()
if (service.getDeploymentConfiguration().isDevModeLiveReloadEnabled()
&& refreshConnection != null
&& TRANSPORT.WEBSOCKET.equals(resource.transport())) {
BrowserLiveReloadAccess access = service.getInstantiator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,26 @@ public void getLiveReload_productionMode_nullIsReturned() {
Assert.assertNull(access.getLiveReload(service));
}

@Test
public void getLiveReload_liveReloadDisabled_nullIsReturned() {
VaadinService service = Mockito.mock(VaadinService.class);
DeploymentConfiguration config = Mockito
.mock(DeploymentConfiguration.class);
Mockito.when(service.getDeploymentConfiguration()).thenReturn(config);
Mockito.when(config.isProductionMode()).thenReturn(false);
Mockito.when(config.isDevModeLiveReloadEnabled()).thenReturn(false);

Assert.assertNull(access.getLiveReload(service));
}

@Test
public void getLiveReload_devMode_contextHasNoReloadInstance_instanceIsCreated() {
VaadinService service = Mockito.mock(VaadinService.class);
DeploymentConfiguration config = Mockito
.mock(DeploymentConfiguration.class);
Mockito.when(service.getDeploymentConfiguration()).thenReturn(config);
Mockito.when(config.isProductionMode()).thenReturn(false);
Mockito.when(config.isDevModeLiveReloadEnabled()).thenReturn(true);

VaadinContext context = Mockito.mock(VaadinContext.class);
Mockito.when(service.getContext()).thenReturn(context);
Expand All @@ -59,6 +72,7 @@ public void getLiveReload_devMode_contextHasReloadInstance_instanceIsReturned()
.mock(DeploymentConfiguration.class);
Mockito.when(service.getDeploymentConfiguration()).thenReturn(config);
Mockito.when(config.isProductionMode()).thenReturn(false);
Mockito.when(config.isDevModeLiveReloadEnabled()).thenReturn(true);

VaadinContext context = Mockito.mock(VaadinContext.class);
Mockito.when(service.getContext()).thenReturn(context);
Expand Down
Loading

0 comments on commit 93f0a40

Please sign in to comment.