Monday, July 13, 2020

OmniFaces 3.7 adds autogenerated sw.js, o:inputHidden and of:stripTags()

OmniFaces 3.7 has been released!

In this version, the WebAppManifestResourceHandler got a new feature: auto-generating an offline-aware service worker file sw.js based on welcome files in web.xml and the configuration in your custom WebAppManifest implementation. With this new feature, the resource handler was renamed to PWAResourceHandler. Further a new component <o:inputHidden> component and a new EL function #{of:stripTags(string)} have been added.

You can find the complete list of additions, changes and fixes at What's new in OmniFaces 3.7.1? list in showcase.

Installation

Non-Maven users: download OmniFaces 3.7.1 JAR and drop it in /WEB-INF/lib the usual way, replacing the older version if any.

Maven users: use <version>3.7.1</version>.

<dependency>
    <groupId>org.omnifaces</groupId>
    <artifactId>omnifaces</artifactId>
    <version>3.7.1</version>
</dependency>

PWAResourceHandler

A WebAppManifestResourceHandler was in OmniFaces 3.6 introduced. This PWAResourceHandler takes it a step further. Previously, it generated only a manifest.json file, which is one of the minimum requirements for a Progressive Web Application (PWA), but now it will also generate an offline-aware sw.js along it which should satisfy the PWA test done by Chrome's Lighthouse tool.

Basically, it will collect all welcome files found in web.xml, build them as JSF views, collect all JSF resource dependencies (any x:outputStylesheet, x:outputScript and x:graphicImage components) found in their component trees, and finally register all of them as offline-available. I.e. the home page should now respond 200 to Lighthouse.

All you need to do is to extend from the org.omnifaces.resourcehandler.WebAppManifest class, implement and override the desired getter methods, put a CDI scope annotation on it such as @ApplicationScoped, and finally reference it in your Facelet template exactly as below:

<link rel="manifest" href="#{resource['omnifaces:manifest.json']}" />

Furthermore, you will also be given the opportunity to explicitly register a special fallback/error page for the "You are offline!" condition. You can do this by overridding the WebAppManifest#getOfflineViewId() method to return the desired JSF view ID.

@Override
public String getOfflineViewId() {
    return "/offline.xhtml";
}

See also the showcase.

If you however would like to make use of the manifest.json alone and disable the offline-aware sw.js feature altogether, then simply override the WebAppManifest#getCacheableViewIds() to return an empty collection. By default, it returns the JSF view IDs of the welcome files encountered in web.xml.

@Override
public Collection<String> getCacheableViewIds() {
    return Collections.emptyList();
}

o:inputHidden

The existing <h:inputHidden> is slightly unintuitive. When the JSF form it is enclosed in is submitted, and another input component within the same form fails conversion or validation, then the value of the <h:inputHidden> won't be set in the backing bean. This makes sense for values submitted by the client, but this doesn't make sense for values submitted by server-controlled code. This way the <h:inputHidden> isn't terribly useful in order to retain request scoped bean properties across postbacks. One solution would be to convert the request scoped bean to a view scoped bean, but this isn't always desireable. It would be undesired when the JSF page in question is required to be entirely stateless.

The new <o:inputHidden> solves this by immediately performing the conversion/validation and updating the model values during the apply request values phase. Of course you could also use a plain vanilla HTML <input type="hidden"> for this in combination with manually grabbing the request parameter, but this is cumbersome and it doesn't transparently support JSF converters.

See also the live demo.

of:stripTags

In case you have a bean property representing a string with potentially some HTML tags, which should be used as some preview string, then you can use the new of:stripTags() function to strip out all HTML tags, leaving only plain text.

Usage example:

#{of:stripTags(bean.html)}

See also the showcase.

What happened to OmniFaces 3.7?

Directly after the 3.7 release I noticed that the sw.js was performing horribly on the showcase site :( These performance problems were unfortunately not immediately visible while developing and testing at localhost. I considered these performance issues to be important enough to warrant a quick hotfix release, so 3.7.1 was released the same day with performance fixes.

So, do not use 3.7 if you plan to make use of the PWAResourceHandler for the autogenerated offline-aware sw.js :)

How about OmniFaces 2.x and 1.1x?

The 2.x got the same bugfixes as 3.7.1 and has been released as 2.7.6. This version is for JSF 2.2 users with CDI. In case you've already migrated to JSF 2.3, use 3.x instead.

The 1.1x is basically already since 2.5 in maintenance mode. I.e. only critical bugfix versions will be released. It's currently still at 1.14.1 (May 2017), featuring the same features as OmniFaces 2.4, but without any JSF 2.2 and CDI things and therefore compatible with CDI-less JSF 2.0/2.1.

No comments: