Skip to content

Commit

Permalink
fix: backwards-compatible offline in V14 legacy mode (#10737)
Browse files Browse the repository at this point in the history
* fix: backwards-compatible offline in V14 legacy mode

* Unit test

* IT test

* Add tsconfig

* Generated tsconfig in V14 bootstrap mode

* NodeTasks test for presence of `tsconfig.json` and `types.d.ts`

* Restore default ctor for PwaConfiguration

* Restore previous ctor for FrontendDependencies

* Restored original createScanner and reverted test use

* Restore original constructor of PwaConfiguration

* Use original PWA ctor without v14 mode flag
  • Loading branch information
Johannes Eriksson committed Apr 22, 2021
1 parent 31a5038 commit e549888
Show file tree
Hide file tree
Showing 17 changed files with 572 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,20 @@ public class PwaConfiguration implements Serializable {
* Default constructor, uses default values.
*/
public PwaConfiguration() {
this(false);
}

/**
* Creates the configuration using default PWA parameters.
*
* @param useV14Bootstrap
* true iff using legacy bootstrap mode
*/
public PwaConfiguration(boolean useV14Bootstrap) {
this(false, DEFAULT_NAME, "Flow PWA", "", DEFAULT_BACKGROUND_COLOR,
DEFAULT_THEME_COLOR, DEFAULT_ICON, DEFAULT_PATH,
DEFAULT_OFFLINE_PATH, DEFAULT_DISPLAY, DEFAULT_START_URL,
new String[] {});
new String[] {}, useV14Bootstrap);
}

/**
Expand All @@ -69,10 +79,22 @@ public PwaConfiguration() {
* the annotation to use for configuration
*/
public PwaConfiguration(PWA pwa) {
this(pwa, false);
}

/**
* Constructs the configuration using the {@link PWA} annotation.
*
* @param pwa
* the annotation to use for configuration
* @param useV14Bootstrap
* true iff using legacy bootstrap mode
*/
public PwaConfiguration(PWA pwa, boolean useV14Bootstrap) {
this(true, pwa.name(), pwa.shortName(), pwa.description(),
pwa.backgroundColor(), pwa.themeColor(), pwa.iconPath(),
pwa.manifestPath(), pwa.offlinePath(), pwa.display(),
pwa.startPath(), pwa.offlineResources());
pwa.startPath(), pwa.offlineResources(), useV14Bootstrap);
}

/**
Expand Down Expand Up @@ -108,6 +130,47 @@ public PwaConfiguration(boolean enabled, String name, String shortName,
String description, String backgroundColor, String themeColor,
String iconPath, String manifestPath, String offlinePath,
String display, String startPath, String[] offlineResources) {
this(enabled, name, shortName, description, backgroundColor, themeColor,
iconPath, manifestPath, offlinePath, display, startPath,
offlineResources, false);
}

/**
* Constructs a configuration from individual values.
*
* @param enabled
* is PWA enabled
* @param name
* the application name
* @param shortName
* the application short name
* @param description
* the description of the application
* @param backgroundColor
* the background color
* @param themeColor
* the theme color
* @param iconPath
* the icon file path
* @param manifestPath
* the `manifest.webmanifest` file path
* @param offlinePath
* the static offline HTML file path
* @param display
* the display mode
* @param startPath
* the start path
* @param offlineResources
* the list of files to add for pre-caching
* @param useV14Bootstrap
* true iff using legacy bootstrap mode
*/
@SuppressWarnings("squid:S00107")
public PwaConfiguration(boolean enabled, String name, String shortName,
String description, String backgroundColor, String themeColor,
String iconPath, String manifestPath, String offlinePath,
String display, String startPath, String[] offlineResources,
boolean useV14Bootstrap) {
this.appName = name;
this.shortName = shortName.substring(0,
Math.min(shortName.length(), 12));
Expand All @@ -116,7 +179,9 @@ public PwaConfiguration(boolean enabled, String name, String shortName,
this.themeColor = themeColor;
this.iconPath = iconPath;
this.manifestPath = manifestPath;
this.offlinePath = offlinePath;
this.offlinePath = offlinePath.isEmpty() && useV14Bootstrap ?
DEFAULT_OFFLINE_PATH :
offlinePath;
this.display = display;
this.startPath = startPath;
this.enabled = enabled;
Expand Down
21 changes: 15 additions & 6 deletions flow-server/src/main/java/com/vaadin/flow/server/PwaRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.slf4j.LoggerFactory;

import com.vaadin.flow.server.communication.PwaHandler;
import com.vaadin.flow.server.startup.ApplicationConfiguration;
import com.vaadin.flow.server.startup.ApplicationRouteRegistry;

import elemental.json.Json;
Expand Down Expand Up @@ -95,20 +96,28 @@ public PwaRegistry(PWA pwa, ServletContext servletContext)
System.setProperty(HEADLESS_PROPERTY, Boolean.TRUE.toString());
}

boolean useV14Bootstrap = false;
ApplicationConfiguration applicationConfiguration = (ApplicationConfiguration) servletContext
.getAttribute(ApplicationConfiguration.class.getName());
if (applicationConfiguration != null) {
useV14Bootstrap = applicationConfiguration.useV14Bootstrap();
}

// set basic configuration by given PWA annotation
// fall back to defaults if unavailable
pwaConfiguration = pwa == null ? new PwaConfiguration()
: new PwaConfiguration(pwa);
pwaConfiguration = pwa == null ? new PwaConfiguration(useV14Bootstrap)
: new PwaConfiguration(pwa, useV14Bootstrap);

// Build pwa elements only if they are enabled
if (pwaConfiguration.isEnabled()) {
URL logo = getResourceUrl(servletContext,
pwaConfiguration.relIconPath());

URL offlinePage = pwaConfiguration.isOfflinePathEnabled()
? getResourceUrl(servletContext,
pwaConfiguration.relOfflinePath())
: null;
URL offlinePage = pwaConfiguration.isOfflinePathEnabled() ?
getResourceUrl(servletContext,
pwaConfiguration.relOfflinePath()) :
null;

// Load base logo from servlet context if available
// fall back to local image if unavailable
BufferedImage baseImage = getBaseImage(logo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,8 @@ private NodeTasks(Builder builder) {
|| enableWebpackConfigUpdate) {
frontendDependencies = new FrontendDependenciesScanner.FrontendDependenciesScannerFactory()
.createScanner(!builder.useByteCodeScanner, classFinder,
builder.generateEmbeddableWebComponents);
builder.generateEmbeddableWebComponents,
builder.useDeprecatedV14Bootstrapping);

if (builder.generateEmbeddableWebComponents) {
FrontendWebComponentGenerator generator = new FrontendWebComponentGenerator(
Expand Down Expand Up @@ -623,8 +624,14 @@ private NodeTasks(Builder builder) {
commands.add(packageCreator);
}

if (frontendDependencies != null) {
addGenerateServiceWorkerTask(builder,
frontendDependencies.getPwaConfiguration());
addGenerateTsConfigTask(builder);
}

if (!builder.useDeprecatedV14Bootstrapping) {
addBootstrapTasks(builder, frontendDependencies);
addBootstrapTasks(builder);

if (builder.connectJavaSourceFolder != null
&& builder.connectJavaSourceFolder.exists()
Expand Down Expand Up @@ -676,8 +683,7 @@ private NodeTasks(Builder builder) {
}
}

private void addBootstrapTasks(Builder builder,
FrontendDependenciesScanner frontendDependencies) {
private void addBootstrapTasks(Builder builder) {
File outputDirectory = new File(builder.npmFolder,
builder.buildDirectory);
TaskGenerateIndexHtml taskGenerateIndexHtml = new TaskGenerateIndexHtml(
Expand All @@ -688,7 +694,10 @@ private void addBootstrapTasks(Builder builder,
new File(builder.generatedFolder, IMPORTS_NAME),
outputDirectory);
commands.add(taskGenerateIndexTs);
}


private void addGenerateTsConfigTask(Builder builder) {
TaskGenerateTsConfig taskGenerateTsConfig = new TaskGenerateTsConfig(
builder.npmFolder);
commands.add(taskGenerateTsConfig);
Expand All @@ -697,13 +706,16 @@ private void addBootstrapTasks(Builder builder,
builder.npmFolder);
commands.add(taskGenerateTsDefinitions);

if (frontendDependencies != null) {
PwaConfiguration pwaConfiguration = frontendDependencies
.getPwaConfiguration();
if (pwaConfiguration.isEnabled()) {
commands.add(new TaskGenerateServiceWorker(
builder.frontendDirectory, outputDirectory));
}
}

private void addGenerateServiceWorkerTask(Builder builder,
PwaConfiguration pwaConfiguration) {
File outputDirectory = new File(builder.npmFolder,
builder.buildDirectory);
if (pwaConfiguration.isEnabled()) {
commands.add(
new TaskGenerateServiceWorker(builder.frontendDirectory,
outputDirectory));
}
}

Expand Down Expand Up @@ -738,7 +750,8 @@ private FrontendDependenciesScanner getFallbackScanner(Builder builder,
if (builder.useByteCodeScanner) {
return new FrontendDependenciesScanner.FrontendDependenciesScannerFactory()
.createScanner(true, finder,
builder.generateEmbeddableWebComponents);
builder.generateEmbeddableWebComponents,
builder.useDeprecatedV14Bootstrapping);
} else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public class FrontendDependencies extends AbstractDependenciesScanner {
private AbstractTheme themeInstance;
private final HashMap<String, String> packages = new HashMap<>();
private final Set<String> visited = new HashSet<>();
private final boolean useV14Bootstrap;
private PwaConfiguration pwaConfiguration;

/**
Expand All @@ -76,7 +77,7 @@ public class FrontendDependencies extends AbstractDependenciesScanner {
* the class finder
*/
public FrontendDependencies(ClassFinder finder) {
this(finder, true);
this(finder, true, false);
}

/**
Expand All @@ -93,7 +94,24 @@ public FrontendDependencies(ClassFinder finder) {
*/
public FrontendDependencies(ClassFinder finder,
boolean generateEmbeddableWebComponents) {
this(finder, generateEmbeddableWebComponents, false);
}

/**
* Tertiary constructor, which allows declaring whether embeddable web
* components should be checked for resource dependencies.
*
* @param finder the class finder
* @param generateEmbeddableWebComponents {@code true} checks the
* {@link com.vaadin.flow.component.WebComponentExporter} classes
* for dependencies. {@code true} is default for
* {@link FrontendDependencies#FrontendDependencies(ClassFinder)}
* @param useV14Bootstrap whether we are in legacy V14 bootstrap mode
*/
public FrontendDependencies(ClassFinder finder,
boolean generateEmbeddableWebComponents, boolean useV14Bootstrap) {
super(finder);
this.useV14Bootstrap = useV14Bootstrap;
log().info(
"Scanning classes to find frontend configurations and dependencies...");
long start = System.nanoTime();
Expand Down Expand Up @@ -435,7 +453,7 @@ private void computePwaConfiguration() throws ClassNotFoundException {
throw new IllegalStateException(ERROR_INVALID_PWA_ANNOTATION);
}
if (dependencies.isEmpty()) {
this.pwaConfiguration = new PwaConfiguration();
this.pwaConfiguration = new PwaConfiguration(useV14Bootstrap);
return;
}

Expand All @@ -454,7 +472,7 @@ private void computePwaConfiguration() throws ClassNotFoundException {
this.pwaConfiguration = new PwaConfiguration(true, name, shortName,
description, backgroundColor, themeColor, iconPath,
manifestPath, offlinePath, display, startPath,
offlineResources.toArray(new String[] {}));
offlineResources.toArray(new String[] {}), useV14Bootstrap);
}

private Logger log() {
Expand All @@ -475,13 +493,9 @@ private Logger log() {
* annotations. However, if no theme is found, {@code Lumo} is used, if
* available.
*
* @param clazz
* the exporter endpoint class
*
* @throws ClassNotFoundException
* if unable to load a class by class name
* @throws IOException
* if unable to scan the class byte code
* @param clazz the exporter endpoint class
* @throws ClassNotFoundException if unable to load a class by class name
* @throws IOException if unable to scan the class byte code
*/
@SuppressWarnings("unchecked")
private void computeExporterEndpoints(Class<?> clazz)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,38 @@ class FrontendDependenciesScannerFactory {
public FrontendDependenciesScanner createScanner(
boolean allDependenciesScan, ClassFinder finder,
boolean generateEmbeddableWebComponents) {
return createScanner(allDependenciesScan, finder,
generateEmbeddableWebComponents, false);
}

/**
* Produces scanner implementation based on {@code allDependenciesScan}
* value.
* <p>
*
* @param allDependenciesScan
* if {@code true} then full classpath scanning strategy is
* used, otherwise byte scanning strategy is produced
* @param finder
* a class finder
* @param generateEmbeddableWebComponents
* checks {@code WebComponentExporter} classes for
* dependencies if {@code true}, doesn't check otherwise
* @param useV14Bootstrap
* whether we are in legacy V14 bootstrap mode
* @return a scanner implementation strategy
*/
public FrontendDependenciesScanner createScanner(
boolean allDependenciesScan, ClassFinder finder,
boolean generateEmbeddableWebComponents,
boolean useV14Bootstrap) {
if (allDependenciesScan) {
// this dep scanner can't distinguish embeddable web component
// frontend related annotations
return new FullDependenciesScanner(finder);
return new FullDependenciesScanner(finder, useV14Bootstrap);
} else {
return new FrontendDependencies(finder,
generateEmbeddableWebComponents);
generateEmbeddableWebComponents, useV14Bootstrap);
}
}
}
Expand Down

0 comments on commit e549888

Please sign in to comment.