Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flow initial pwa #4334

Merged
merged 50 commits into from
Jul 11, 2018
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
74ccbf0
Adds automatic PWA -initialization for all Flow-projects.
mikotin Jun 19, 2018
110a643
Renamed Manifest to PWA.
mikotin Jun 25, 2018
b03bdb0
Added missing type from icons
mikotin Jun 26, 2018
1953c59
Added missing href setting
mikotin Jun 26, 2018
3538cbf
Changed pwa handlers to a single handler with pre-calculated responses.
mikotin Jun 26, 2018
8908c3b
Fixed icon inject for offline page.
mikotin Jun 26, 2018
fc2a561
Updated pwa properties to better support add to home screen -function…
mikotin Jun 26, 2018
f52538a
Cleared up the code and added comments.
mikotin Jun 26, 2018
5b0b1cc
Added support for custom offline resources.
mikotin Jun 26, 2018
10c19f1
Added missing documentation, moved PWARegistry to server -package.
mikotin Jun 27, 2018
97d580c
Added required docs and fixed minor issues reported by bot.
mikotin Jun 27, 2018
efeb58e
Added meta tags for better PWA support.
mikotin Jun 27, 2018
e19249a
Fixed commented issues.
mikotin Jun 28, 2018
b942b51
Fixed comments.
mikotin Jun 28, 2018
45f9931
Fixed comments.
mikotin Jun 28, 2018
96451c3
Refactored Icon class and added missing copyright headers.
mikotin Jun 29, 2018
11454ad
Moved PWA scanning to route registry initializer.
mikotin Jun 29, 2018
3c4a794
Fixed reported issues
mikotin Jun 29, 2018
e0ab2da
Changed general exception to a named exception.
mikotin Jul 1, 2018
067fb12
Removed unused import.
mikotin Jul 1, 2018
2185806
Replaced repeated strings with constants.
mikotin Jul 1, 2018
a5ab9fe
Minor code style change. Added tesource stream close handling.
mikotin Jul 1, 2018
c8b77e2
Changed resource reading as informed by bot.
mikotin Jul 1, 2018
a73ebe4
Added missing copyright header.
mikotin Jul 2, 2018
9a44794
Added tests for PWA annotation.
mikotin Jul 4, 2018
f7ad12c
Changed default logo for pwa
mikotin Jul 4, 2018
d5d926f
Default display changed to standalone and updated default resources.
mikotin Jul 5, 2018
ec3e500
Fixed theme-color meta tag.
mikotin Jul 5, 2018
eb57b39
Fixed pwa meta tags and tests for those.
mikotin Jul 5, 2018
3a74bd5
Changed the copyright year to 2018. (Came back to the future)
mikotin Jul 5, 2018
d8adc3f
Changed the copyright year and added constant for repeated string.
mikotin Jul 5, 2018
ca2d2f4
Merge branch 'master' into flow-initial-pwa
Jul 5, 2018
6c4b20a
Styling fixes. (#4365)
SomeoneToIgnore Jul 5, 2018
15a789f
Remove unneeded CSS property.
Jul 5, 2018
663cd54
Added local serving of needed Workbox -files.
mikotin Jul 6, 2018
c71e058
Merge branch 'flow-initial-pwa' of ssh://github.com/vaadin/flow into …
mikotin Jul 6, 2018
682c3ad
Removed enabled from PWA annotation.
mikotin Jul 6, 2018
0d67035
Cleared silly issues that were left in the code.
mikotin Jul 6, 2018
efb7050
Moved fixed value out of if clause.
mikotin Jul 6, 2018
b2bd0cd
Replaced getCurrent() with proper way.
mikotin Jul 6, 2018
3612a12
Added synchronized for to lazy initializator.
mikotin Jul 6, 2018
38c0460
Removed unused import.
mikotin Jul 6, 2018
e1fe75d
Changed private field to AtomitRefence.
mikotin Jul 6, 2018
b4c69d0
Updated version.
mikotin Jul 6, 2018
ff85742
Fixed constant.
mikotin Jul 6, 2018
34eeaa7
Merge branch 'master' into flow-initial-pwa
Jul 10, 2018
6af74cd
Fix sonar issues.
Jul 10, 2018
4da44a9
Code review fixes.
Jul 10, 2018
689730a
Fix NPE.
Jul 10, 2018
a55390a
Replace string concatenation with append.
Jul 11, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
import elemental.json.JsonObject;
import elemental.json.JsonValue;
import elemental.json.impl.JsonUtil;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
Expand All @@ -94,6 +93,7 @@ public class BootstrapHandler extends SynchronizedRequestHandler {
private static final String DEFER_ATTRIBUTE = "defer";
static final String VIEWPORT = "viewport";
private static final String META_TAG = "meta";
private static final String SCRIPT_TAG = "script";

/**
* Location of client nocache file, relative to the context root.
Expand Down Expand Up @@ -461,7 +461,7 @@ private static void exportUsageStatistics(Document document) {
}).collect(Collectors.joining("\n"));

if (!registerScript.isEmpty()) {
document.body().appendElement("script").text(registerScript);
document.body().appendElement(SCRIPT_TAG).text(registerScript);
}
}

Expand Down Expand Up @@ -569,6 +569,7 @@ private static void writeBootstrapPage(VaadinResponse response, String html)
private static List<Element> setupDocumentHead(Element head,
BootstrapContext context) {
setupMetaAndTitle(head, context);
setupPwa(head, context);
setupCss(head, context);

JsonObject initialUIDL = getInitialUidl(context.getUI());
Expand Down Expand Up @@ -701,6 +702,51 @@ private static void setupMetaAndTitle(Element head,
});
}

private static void setupPwa(Element head, BootstrapContext context) {
VaadinService vaadinService = context.getSession().getService();
if (vaadinService == null) {
return;
}

PwaRegistry registry = vaadinService.getPwaRegistry();
if (registry == null) {
return;
}

PwaConfiguration config = registry.getPwaConfiguration();

if (config.isEnabled()) {
// Describe PWA capability for iOS devices
head.appendElement(META_TAG)
.attr("name", "apple-mobile-web-app-capable")
.attr(CONTENT_ATTRIBUTE, "yes");

// Theme color
head.appendElement(META_TAG).attr("name", "theme-color")
.attr(CONTENT_ATTRIBUTE, config.getThemeColor());
head.appendElement(META_TAG)
.attr("name", "apple-mobile-web-app-status-bar-style")
.attr(CONTENT_ATTRIBUTE, config.getThemeColor());

// Add manifest
head.appendElement("link").attr("rel", "manifest").attr("href",
config.getManifestPath());

// Add icons
for (PwaIcon icon : registry.getHeaderIcons()) {
head.appendChild(icon.asElement());
}

// Add service worker initialization
head.appendElement(SCRIPT_TAG)
.text("if ('serviceWorker' in navigator) {\n"
+ " window.addEventListener('load', function() {\n"
+ " navigator.serviceWorker.register('"
+ config.getServiceWorkerPath() + "');\n"
+ " });\n" + "}");
}
}

private static void appendWebComponentsPolyfills(Element head,
BootstrapContext context) {
VaadinSession session = context.getSession();
Expand Down Expand Up @@ -751,7 +797,7 @@ private static Element createInlineJavaScriptElement(

private static Element createJavaScriptElement(String sourceUrl,
boolean defer) {
Element jsElement = new Element(Tag.valueOf("script"), "")
Element jsElement = new Element(Tag.valueOf(SCRIPT_TAG), "")
.attr("type", "text/javascript").attr(DEFER_ATTRIBUTE, defer);
if (sourceUrl != null) {
jsElement = jsElement.attr("src", sourceUrl);
Expand Down
150 changes: 150 additions & 0 deletions flow-server/src/main/java/com/vaadin/flow/server/PWA.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright 2000-2018 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.flow.server;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Defines application PWA properties.
*
* Annotation activates automatic
* <a href="https://developer.mozilla.org/en-US/Apps/Progressive">PWA</a>
* injecting.
* <p>
* Only one annotation for application is supported. Annotation must be placed
* to master layout.
*
* Application annotated the annotation will add following capabilities to Flow
* application:
*
* <ul>
* <li>handle manifest.json
* <li>handle sw.js (service worker), which will enable simple offline fallback
* and file caching
* <li>handle default (static) offline html page
* <li>handle different versions (sizes) of the given logo
* <li>inject needed tags to the app's page header
* </ul>
*
* Any of the handled resources can be explicitly overridden with static file in
* public resources. For example, if {@literal manifest.json} is available in
* webapp root folder it will be served instead of generated
* {@literal manifest.json}. Same applies for service worker and generated
* icons.
*
* @see <a href=
* "https://developer.mozilla.org/en-US/Apps/Progressive">https://developer.mozilla.org/en-US/Apps/Progressive</a>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PWA {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of methods (attributes) in this annotation.
So in the worst case the usage of this annotation will look like
@PWA(offlinePath="abc", manifestPath="foo", logoPath="bar", name="sdfsdf", shortName="cccc",...........................)

Looks inconvenient to me.

I'm not sure exactly how it may be improved.
But may be use PWA as an enabler and delegate all the properties to the class like it's done for @Theme annotation?

I would change in this case PWA to EnablePWA and add class or interface which contains all the methods from here (let's say its name is PWAConfig).
Then EnablePWA would be:

public @interface EnablePWA {
          Class<? extends PWAConfig> value();
}

Then there will be an additional responsibility to instantiate the provided class

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aye, there are quite a lot of those properties. But I like the developer experience of having all that in that annotation: that way adding values and/or checking default values is supported directly with IDE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


/**
* Path to the static offline html file.
*
* Defaults to (relative) {@literal offline.html} with default configuration
* that is {@literal webapp/offline.html}
*
* If offline file is not found, falls back to default offline page.
*
* @return path to the static offline html file
*/
String offlinePath() default PwaConfiguration.DEFAULT_OFFLINE_PATH;

/**
* Path to the manifest file.
*
* Defaults to (relative) {@literal manifest.json} with default
* configuration that is {@literal webapp/manifest.json}
*
* @return path to the manifest file
*/
String manifestPath() default PwaConfiguration.DEFAULT_PATH;

/**
* Path to the application logo file.
*
* Defaults to (relative) {@literal icons/logo.png} with default
* configuration that is {@literal webapp/manifest.json}
*
* If the specified logo file is not found, the default one will be used.
* The file is also used to create different sizes of logo.
*
* @return path to the application logo file
*/
String logoPath() default PwaConfiguration.DEFAULT_LOGO;

/**
* Name of the application.
*
* @return name of the application
*/
String name();

/**
* Short name for the application. Maximum of 12 characters.
*
* @return short name for the application
*/
String shortName();

/**
* Description of the application.
*
* @return description of the application
*/
String description() default "";

/**
* Theme color of the application.
*
* The theme color sets the color of the application's tool bar and
* application's color in the task switcher.
*
* @return theme color of the application
*/
String themeColor() default PwaConfiguration.DEFAULT_THEME_COLOR;

/**
* Background color of the application.
*
* The background color property is used on the splash screen when the
* application is first launched.
*
* @return Background color of the application
*/
String backgroundColor() default PwaConfiguration.DEFAULT_BACKGROUND_COLOR;

/**
* Defines the developers’ preferred display mode for the website.
*
* Possible values: fullscreen, standalone, minimal-ui, browser
*
* @return display mode of application
*/
String display() default PwaConfiguration.DEFAULT_DISPLAY;

/**
* Offline resources to be cached using the service worker.
*
* @return offline resources to be cached
*/
String[] offlineResources() default {};

}