Workbox not recognizing root url regex /^\/$/ added to navigation fallback blacklist - progressive-web-apps

I have a SPA with service worker generated with Workbox webpack plugin. The root url "/" is a separate home page for my website and not part of my SPA, so I want my service worker to not fallback to the app shell of my SPA but instead fetch the home page from server when I navigate to "/". I know workbox has the navigationFallbackBlacklist option to specify url patterns that are not a part of the SPA. This option is working for several other url paths that my website have but not the root url. I am wondering if there are some work arounds for my use case.

Working for mi:
With workbox-build and generateSw:
...
runtimeCaching: [
{
urlPattern: /^https:\/\/(www\.)?test.local(\/)?$/,
handler: 'NetworkFirst',
options: {
cacheName: 'home-page',
expiration: {
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 DAYS
maxEntries: 1
}
}
},
Or writing manually:
workbox.routing.registerRoute(
/^https:\/\/(www\.)?test.local(\/)?$/,
workbox.strategies.networkFirst({
cacheName: 'home-page',
...
})
)
(NetworkFirst handler mode is important, in many cases)

Related

How to solve PWA Caching issue, currently it need double refresh?

My clients are reporting a serious user experience issue in a web application after converting it into PWA.
I need to refresh the browser twice after a dynamic update in this PHP application. It includes sharing a new post, delete, adding a comment etc. Everything works fine in the database. But cached version of the same page appears after the first refresh. It even brings up the page of a logged out user, if we access it from a new account.
I have also found few fix suggesting to modify service worker file to fetch updates directly from server. Service worker code displaying below
importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
if (workbox) {
console.log("Yay! Workbox is loaded !");
workbox.precaching.precacheAndRoute([]);
/* cache images in the e.g others folder; edit to other folders you got
and config in the sw-config.js file
*/
workbox.routing.registerRoute(
/(.*)others(.*)\.(?:png|gif|jpg)/,
new workbox.strategies.CacheFirst({
cacheName: "images",
plugins: [
new workbox.expiration.Plugin({
maxEntries: 50,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
})
]
})
);
/* Make your JS and CSS âš¡ fast by returning the assets from the cache,
while making sure they are updated in the background for the next use.
*/
workbox.routing.registerRoute(
// cache js, css, scc files
/.*\.(?:css|js|scss|)/,
// use cache but update in the background ASAP
new workbox.strategies.StaleWhileRevalidate({
// use a custom cache name
cacheName: "assets",
})
);
// cache google fonts
workbox.routing.registerRoute(
new RegExp("https://fonts.(?:googleapis|gstatic).com/(.*)"),
new workbox.strategies.CacheFirst({
cacheName: "google-fonts",
plugins: [
new workbox.cacheableResponse.Plugin({
statuses: [0, 200],
}),
],
})
);
// add offline analytics
workbox.googleAnalytics.initialize();
/* Install a new service worker and have it update
and control a web page as soon as possible
*/
workbox.core.skipWaiting();
workbox.core.clientsClaim();
} else {
console.log("Oops! Workbox didn't load 👺");
}

Meteor FlowRouter: replace path in history for restricted route

I'm using FlowRouter in a Meteor app. In one case, a resource is not available until a certain date/time, so we redirect to another route. Is there anyway to replace the route to the restricted resource with the path to the redirect such that the restricted resource route will not appear in the browser history. Doing will make the history (using back, forward) more UX friendly.
I can achieve this in FlowRouter's triggersEnter for the route, by stepping outside of FlowRouter with something like:
if(restricted) {
return window.location.replace(`/waitingroom/${resourceId}/user/${Meteor.userId()}`);
}
...but this causes a page reload, which is sort of undesirable.
Any idears?
Functions pass to triggersEnter have the 2nd param named redirect you can use it to redirect to other pages without reloading the page and having a clean history:
FR.route('/restricted-route', {
name: 'RestrictedRoute',
triggersEnter: [function(context, redirect) {
redirect('/replace-route');
}]
});
FR.route('/replace-route', {
name: 'ReplaceRoute',
action() {
// ...
}
});
Updated
I am not sure why it's required to be sync. Anyway FlowRouter uses Page.js behind the scene to do navigation, if you can not use redirect then this should work:
FR.route('/restricted-route', {
name: 'RestrictedRoute',
triggersEnter: [function(context, redirect) {
Meteor.setTimeout(() => {
FlowRouter._page.replace('/replace-route');
}, 1000);
}]
});
Note: this is not the public API, therefore you should test it carefully before using in production.

Durandal JS: typing url without hash give HTTP Error 404.0 - Not Found

I am building a SPA application using Durandaljs. When I enter a URL WITHOUT hash, it shows the error: HTTP error 404.0 - NOT FOUND. However, it is working fine WITH hash.
Example:
www.domain.com/page => HTTP error 404.0 - NOT FOUND
www.domain.com/#page = > working fine.
How can I map the www.domain.com/page to www.domain.com/#page?
In order for pushState to work correctly in your app (including deep linking), you must configure the router for pushState and tell the server to ignore all but certain paths/routes.
The server should ignore paths that contain resources or services used by your SPA, and should always send the Durandal.cshtml (or whatever you name it) for these ignored routes.
These routes should be ignored even if there's additional route info in the request. This will allow for deep linking using pushState-style URLs.
Here's the MVC routing from a Durandal-based app I recently completed:
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Ignore("{resourcedir}/{*resource}",
new {resourcedir = #"(api|breeze|app|scripts|content|assets|signalr)"});
routes.MapRoute(
name: "Default",
url: "{*sparoute}",
defaults: new { controller = "Durandal", action = "Index"});
}
Basically, we're telling the server to ignore any requests that start with:
api/
breeze/
app/
scripts/
content/
assets/
signalr/
We're ignoring api, breeze and singlar because WEBApi and SignalR will handle those requests. Also, app, scripts, content, and assets are ignored because the underlying ASP.NET engine will serve those requests.
The final statement (routes.MapRoute) causes all non-ignored requests to send back the default page (the only real page in the SPA).
For example, www.domain.com/page will send the same response from the server as if you'd asked for www.domain.com/. Once the SPA loads and Durandal's router/history has initialized, the suffix is converted to hash if needed (like you're using IE) and is then dispatched through the router.
Note that if your application is not rooted at /, you need to specify the root path. You should also include hashChange: true so that your application works in IE, like this:
router.activate({ pushState: true, hashChange: true, root: '/approot' })
You can, I'm using it in my latest Durandal site which is based on the DurandalAuth template.
When you are initializing your router, set pushState: true, like this:
return router.map([
{ route: 'somroute', moduleId: 'somroute', title: 'Home', nav: true, hash: "#somroute" }
])
.buildNavigationModel()
.mapUnknownRoutes("notfound", "notfound")
.activate({ pushState: true });
You can see a working example on my site: noadou

Reverse routing on an application deployed in a Tomcat context

I am developing a Play 1.2.5 application that will be installed in a Tomcat context:
http://mytomcat:8080/myapp
And in my routes file I have:
GET /companies/{companyID}/employees Employees.getForCompany
As per the instructions for deploying a Play application in a Tomcat context, I am generating URLs exlusively using the Reverse Router. This works fine, but I am not sure what to do in the case of a jQuery method such as an Ajax request of this style:
var companyID = $('#companies').find(":selected").val();
$.ajax({
url : "#{Employees.getForCompany(companyID)}",
...
});
Obviously the value of companyID isn't known at the time of the generation of the HTML and the resolution of routes by the reverse router.
The only solution that I can see is to reconfigure my routes file so that the URLs are different and the parameters are always at the end, but that makes the REST URLs less logical.
GET /companies/employees/{companyID} Employees.getForCompany
Is there a better way?
I have found the solution myself - Play includes the jsAction tag which generates a function that builds the correct URL:
var companyURL = #{jsAction #Employees.getForCompany(':companyID') /}
$.ajax({
url : companyURL({companyID:companyID}),
...
});
Like that I can maintain the preferred routes mapping:
GET /companies/{companyID}/employees Employees.getForCompany

My app cant update cache while pwa is active on laravel

I'm making an application with PWA but when in the database I update something in the main URL that appears no changes have occurred, and I have to clear the cache that is in the service worker, whereas in mobile, the end user might not have to clear the cache first to use the application. , is there a solution to my problem?
I have done several alternatives such as masking the URL to avoid caching the service worker but I know it's not efficient
it's my service worker file
importScripts('https://storage.googleapis.com/workboxcdn/releases/4.3.1/workbox-sw.js');
if (workbox) {
workbox.setConfig({
debug: true
});
// top-level routes we want to precache
workbox.precaching.precacheAndRoute(['/123', '/123']);
// injected assets by Workbox CLI
workbox.precaching.precacheAndRoute([
//my precache data is here
]);
// match routes for homepage, blog and any sub-pages of blog
workbox.routing.registerRoute(
/^\/(?:()?(\/.*)?)$/,
new workbox.strategies.NetworkFirst({
cacheName: 'static-resources',
})
);
// js/css files
workbox.routing.registerRoute(
/\.(?:js|css)$/,
new workbox.strategies.NetworkFirst({
cacheName: 'static-resources',
})
);
// images
workbox.routing.registerRoute(
// Cache image files.
/\.(?:png|jpg|jpeg|svg|gif)$/,
// Use the cache if it's available.
new workbox.strategies.NetworkFirst({
// Use a custom cache name.
cacheName: 'image-cache',
plugins: [
new workbox.expiration.Plugin({
// Cache upto 50 images.
maxEntries: 50,
// Cache for a maximum of a week.
maxAgeSeconds: 7 * 24 * 60 * 60,
})
],
})
);
}
I don't see any logic in your service worker to invalidate cached data/responses when you post updates to the server. You will have to add that logic to your fetch handler.
FYI workbox does not include that by default you will have to create your own logic for that. Workbox only has some common caching strategies in place. It can't provide modules for every site's custom caching scenarios. That is why the tool is extensible.