Skip to content
This repository has been archived by the owner on Apr 21, 2020. It is now read-only.

WIP: Explore progressive web app for offline use #112

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

rgrempel
Copy link
Contributor

@rgrempel rgrempel commented Jun 7, 2017

See #111.

@rgrempel rgrempel changed the title Explore progressive web app for offline use WIP: Explore progressive web app for offline use Jun 7, 2017
@rgrempel
Copy link
Contributor Author

rgrempel commented Jun 7, 2017

Here are some thoughts on initial work on integrating progressive web app concepts, using service workers.

The service worker script listens for certain events and can react to them. The events include "fetching" a URL ... so, the service worker can insert itself between the app and the network, deciding to fulfil requests in some other way (e.g. from a cache ...) instead of, or in addition to, actually sending the request over the network. So, you might think of the service worker script itself as a kind of middleware, sitting between your app and the network. In fact, the service worker script runs in a specialized context ... it can't directly change the DOM etc. -- it can only listen for certain events and react to them. (Fortunately, it can write to the console ...).

You could imagine trying to write the service worker script in Elm, but it's probably more trouble than it's worth. In fact, to skip ahead, it's probably more trouble than it's worth to write it at all, given that sw-precache will write it for you ...

The other thing you need to do is "register" your service-worker, so the browser knows to use it. Here, that fits nicely with our app.js.

Now, there are ultimately two things one wants to deal with when offline:

  • Loading the app at all.
  • Dealing with data.

For loading the app at all, relying on sw-precache in the build stage seems like the easiest approach. The configuration for that is in the gulpfile. We cache two types of things here:

  • Our "local" files ... that is, the HTML, CSS, etc. that we normally serve.
  • Some CDN files that we reference

So, what's the result so far? To test, try this procedure:

  • Checkout the master branch.
  • Run gulp
  • Navigate to the app in your browser (this should work).
  • End the gulp process.
  • Reload the page in your browser.

This won't work, of course -- the frontend isn't being served, so you get this:

image

Now, try this:

  • Checkout this branch
  • Run gulp
  • Navigate to the app in your browser (should work).
  • End the gulp process
  • Reload the page in your browser.

Tada! Everything keeps working, even though we're not actually serving the frontend any longer. In fact, because the backend is still running, everything is completely useable.

Now, if you've been following along so far, there is one gotcha I should mention. The service worker we've installed now "owns" whatever top-level domain you're using. So, if you are using http://localhost:3000, you'll now get the cached site even if the network is serving something else now. So, in the long run, this is probably best for production sites rather than in dev mode -- it's just convenient now to have it work in dev mode.

To kill the service-worker in Chrome, go to this URL:

chrome://serviceworker-internals/

You'll see all your service workers, and you can unregister the one for http://localhost:3000/ (for instance) to use some different site.

Another "gotcha" is that the service-worker doesn't work very well with browserSync yet. I've tried to fix that a bit -- the best I've gotten so far is that you need to manually refresh the browser a couple of times and then you get the update. So, either that needs to be fixed better, or (more probably) we'd eventually just configure this for production, not dev mode.

So, to recap, what we've got so far is a fully viable proof-of-concept for reloading the browser without serving the frontend at all. (Ultimately, we'd probably want to reconfigure this so that it only is applied in production, or fix some of the "gotchas" for dev mode.)

Now, what about the backend? So far, the backend has still been running. What if we turn that off as well -- e.g. have no network access?

For that, we actually have a choice to make. What we've done so far -- making the frontend load & run without serving it -- can't really be done "inside" our Elm app, since there is no Elm app until we load the frontend. However, given that we can load the frontend even if we're not connected, we've got a choice for the rest of it -- that is, a choice for what to do about the absence of the backend.

In theory, the service worker is capable of dealing with the absence of the backend. it intercepts network requests, after all, so we can cache data or simulate responses, or whatever.

However, I'm not sure whether that's necessary or desirable. The Elm app itself, after all, can know whether it is online or offline, and respond to error conditions (like the unavailability of the network), and do the right thing (whatever that is). For instance, the Elm app can have its own mechanism for caching data and using it instead of network data, and doing updates in local storage until the network is available, or whatever.

My gut feeling is that it is going to be better to deal with the absence of the backend in the Elm app itself, rather than at the service worker level.

  • Whatever complex logic is required will be easier in Elm than Javascript.
  • It will be easier to reflect what is going on in the UI (to which the service-worker has no access).

@rgrempel
Copy link
Contributor Author

rgrempel commented Jun 7, 2017

Note that we could use a similar approach to generate a cache manifest for browsers (like Safari) that don't support service workers. (Similar in the sense that it would be a step in the gulpfile).

@rgrempel
Copy link
Contributor Author

rgrempel commented Jun 7, 2017

So, I'll stop there for now. I would not suggest actually merging this yet -- it has too many gotchas in dev mode at the moment -- but they could either be fixed, or I can make this work in production mode instead (it was easier in dev mode for the proof-of-concept).

@AronNovak
Copy link
Member

@amitaibu should we rely on this one when thinking about offline capabilities as discussed today?
Then does it make sense to continue this for the benefit of the client project?

@amitaibu
Copy link
Member

amitaibu commented Jul 2, 2017

@rgrempel I believe this PR is actually mostly done, right? Only thing I'd change is the port in gulp to be 3100 or something, so it doesn't hijack other projects.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants