Skip to content

Commit

Permalink
fix(offline): navigation fallback (#9280)
Browse files Browse the repository at this point in the history
Fixes #9218.

This makes navigation fallback (offline start) use the same service worker logic as we use for `offlinePath`, just using the app shell route `/` instead of the route to offline page for the cache entry to be returned. I did some manual testing and this does seem to fix the issues described in #9218.

The added IT seems to be a false negative (always passes) and doesn't fail even without the fix, test can be fixed in #9314
  • Loading branch information
Haprog authored and Johannes Eriksson committed Nov 4, 2020
1 parent 3c8d310 commit b4a8c3e
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 31 deletions.
52 changes: 21 additions & 31 deletions flow-server/src/main/resources/sw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,33 @@ import {skipWaiting, clientsClaim} from 'workbox-core';
import {matchPrecache, precacheAndRoute} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';
import {PrecacheEntry} from 'workbox-precaching/_types';
import {NetworkFirst, NetworkOnly} from 'workbox-strategies';
import {NetworkOnly} from 'workbox-strategies';

skipWaiting();
clientsClaim();

let navigationFallback;
// @ts-ignore: OFFLINE_PATH_ENABLED is defined by webpack.generated.js
if (OFFLINE_PATH_ENABLED) {
// @ts-ignore
const offlinePath = '/' + OFFLINE_PATH;
const networkOnly = new NetworkOnly();
navigationFallback = new NavigationRoute(async (params: any) => {
// Use offlinePath fallback if offline was detected
if (!self.navigator.onLine) {
const offlinePathPrecachedResponse = await matchPrecache(offlinePath);
if (offlinePathPrecachedResponse) {
return offlinePathPrecachedResponse;
}
const appShellPath = '/';
// @ts-ignore: OFFLINE_PATH_ENABLED and OFFLINE_PATH are defined by webpack.generated.js
const offlinePath = OFFLINE_PATH_ENABLED ? '/' + OFFLINE_PATH : appShellPath;
const networkOnly = new NetworkOnly();
const navigationFallback = new NavigationRoute(async (params: any) => {
// Use offlinePath fallback if offline was detected
if (!self.navigator.onLine) {
const offlinePathPrecachedResponse = await matchPrecache(offlinePath);
if (offlinePathPrecachedResponse) {
return offlinePathPrecachedResponse;
}
}

// Sometimes navigator.onLine is not reliable, use fallback to offlinePath
// also in case of network failure
try {
return await networkOnly.handle(params);
} catch (error) {
return (await matchPrecache(offlinePath)) || error;
}
});

// Sometimes navigator.onLine is not reliable, use fallback to offlinePath
// also in case of network failure
try {
return await networkOnly.handle(params);
} catch (error) {
return (await matchPrecache(offlinePath)) || error;
}
});
} else {
const appShellCacheKey = '/';
navigationFallback = new NavigationRoute(new NetworkFirst({
plugins: [
// Always use app shell cache key instead of original request URL
{ cacheKeyWillBeUsed: async () => appShellCacheKey },
]
}));
}
registerRoute(navigationFallback);

// @ts-ignore: __WB_MANIFEST is injected by the InjectManifest plugin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,38 @@ public void testOfflineStart() throws IOException {
}
}

@Test
public void testOfflineStart_nonRootReload() throws IOException {
getDriver().get(getRootURL() + "/");
waitForServiceWorkerReady();

// Set offline network conditions in ChromeDriver
setConnectionType(NetworkConnection.ConnectionType.AIRPLANE_MODE);

try {
$("main-view").first().$("a").id("menu-another").click();

// Wait for component inside shadow root as there is no vaadin
// to wait for as with server-side
waitUntil(input -> $("another-view").first().$("div").id("another-content")
.isDisplayed());

// Reload the page in offline mode
executeScript("window.location.reload();");
waitUntil(webDriver -> ((JavascriptExecutor) driver)
.executeScript("return document.readyState")
.equals("complete"));

MatcherAssert.assertThat(getDriver().getCurrentUrl(),
CoreMatchers.endsWith("/another"));
Assert.assertTrue(getInShadowRoot(findElement(By.tagName("another-view")),
By.id("another-content")).isDisplayed());
} finally {
// Reset network conditions back
setConnectionType(NetworkConnection.ConnectionType.ALL);
}
}

@Test
public void openTsView_goOffline_navigateToOtherTsView_navigationSuccessful() throws IOException {
getDriver().get(getRootURL() + "/about");
Expand Down

0 comments on commit b4a8c3e

Please sign in to comment.