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

offliner #14

Closed
delapuente opened this issue Oct 20, 2015 · 10 comments
Closed

offliner #14

delapuente opened this issue Oct 20, 2015 · 10 comments

Comments

@delapuente
Copy link

Source: https://github.com/delapuente/offliner

Goal

Offliner is a library that implements a lifecycle for web applications utilizing service workers. The primary goal of offliner is to enable developers to provide an offline experience for their applications and easily dispatch updates to users as needed.

Roadmap

For each stage to be considered done, the latest implementation should work both in Firefox and Chrome latest stable versions.

Stage I

Improve documentation and change some API nomenclature to make it obvious we are providing a web app lifecycle: we put the abstract logic, you provide the specific implementation:

  1. Update README.md
  2. Update API

Stage II

Provide a basic and separated toolbox for strategies on installing, serving and updating. The toolbox is intended to mimic former appcache capabilities.

  1. Install from a list of URL
  2. Serve from cache
  3. Serve from network
  4. Serve from a fallback map
  5. Update on install

Stage III

Integration with GitHub:

  1. Provide a prefetch middleware to install from a GitHub deployment
    1. Download the zip
    2. Deflate and add its contents to offline cache
  2. Provide an update middleware to update from GitHub
    1. Track the HEAD hash of gh-pages branch
    2. Re-download and reinstall the zip
  3. Provide a set of sources to serve from the offline cache

Stage IV

Integrate with Gaia Component ServiceWorkerWare:

  1. Make installing, serving and updating libraries compatible with sww.
  2. Allow an instance of offliner to be installed as sww's middleware.
@delapuente
Copy link
Author

@marco-c @mykmelez what do you think about this roadmap for offliner? Any feedback is welcome!

@mykmelez
Copy link
Contributor

mykmelez commented Nov 2, 2015

@delapuente I'd like to know more about the use cases for offliner, and how it meets particular needs of certain developers. When would a developer use offliner versus writing a service worker entirely from scratch or using a tool like sw-precache that entirely writes the service worker for them? Is there a "niche" or "sweet spot" for this tool with a particular use case or a certain kind of developer? Are there other tools that it integrates with, such that it's especially handy when using those tools (the way that broccoli-serviceworker is especially handy when developing an Ember app with Broccoli)?

@delapuente
Copy link
Author

Notice I'm going to talk as if offliner were fully developed.

Yes, there are two main user stories:

  • As a traditional web app developer, I want my web application to behave as a native application providing means to be installed, updated and removed if required.
  • As a service worker developer, I want offliner functionality to be composable with other functionality of my own.

When would a developer use offliner versus writing a service worker entirely from scratch or using a tool like sw-precache that entirely writes the service worker for them?

Using offliner the developer can integrate (not mix) with its own service worker and can clearly distinguish responsibilities event when managing the lifecycle provided by offliner thanks to its pseudodeclarative syntax.

Is there a "niche" or "sweet spot" for this tool with a particular use case or a certain kind of developer?

Yes, the traditional web app developer is that who is focused on client content and is unaware of / not interested in service workers technology. He wants a way to quickly make some assets available during offline in order to provide a safe UX beyond the network error of the UA.

Are there other tools that it integrates with, such that it's especially handy when using those tools (the way that broccoli-serviceworker is especially handy when developing an Ember app with Broccoli)?

Not at the moment, offliner is meant to be a building block. Automatic asset list generators like that in oghliner is a good example of integration. Wrappers for Ember or Angular, even using web-components are feasible as well.

Summarizing, the design principles of offliner should be abstraction, isolation and interoperability.

@mykmelez
Copy link
Contributor

mykmelez commented Nov 4, 2015

Yes, the traditional web app developer is that who is focused on client content and is unaware of / not interested in service workers technology. He wants a way to quickly make some assets available during offline in order to provide a safe UX beyond the network error of the UA.

Hmm, this audience seems better served by higher-level tools like Oghliner and sw-precache that write your service worker for you, so you don't have to write it yourself (or even be aware of what it is, to some degree).

As a service worker developer, I want offliner functionality to be composable with other functionality of my own.

Using offliner the developer can integrate (not mix) with its own service worker and can clearly distinguish responsibilities event when managing the lifecycle provided by offliner thanks to its pseudodeclarative syntax.

This audience makes more sense for a tool like offliner, although I'm not sure exactly what it means to be a "service worker developer." I imagine that this describes a kind of developer who writes service workers to handle a variety of tasks, f.e. push notifications, and would also like to use them to offline their app's assets, but doesn't necessarily want to write that code from scratch.

In that case, a tool like Oghliner/sw-precache might be too high-level, as it makes most decisions for you, and it doesn't offer much support for integrating with other service worker code (although it does offer some support).

I do wonder about the relative value of integrating service worker code for different tasks versus maintaining multiple service workers, each handling a different task. That seems worth exploring, since a higher-level tool might also satisfy those developers if it lets them offline their assets without needing to integrate the offlining code with their other service worker code.

It'd also be interesting to look at a comparison of a basic offlining service worker developed from scratch versus one developed using offliner. (Apologies if this is already available and I just don't know about it!)

@delapuente
Copy link
Author

Hmm, this audience seems better served by higher-level tools like Oghliner and sw-precache that write your service worker for you, so you don't have to write it yourself (or even be aware of what it is, to some degree).

This is why the API of offliner tries to hide the fact you're dealing with SW (maybe I didn't success completely on this) and present you with a higher abstraction of application lifecycle. See
the worker example, for instance.

I do wonder about the relative value of integrating service worker code for different tasks versus maintaining multiple service workers, each handling a different task.

Even maintaining different service workers per responsibility, you are limited to only one service worker by scope so being able to compound some service worker-building blocks is something desirable. You can see our work in serviceworkerware for an example of these building blocks.

Why I'm not using serviceworkerware? Well, implementing a complete lifecycle middleware would lead to a reimplementation of everything what is already done in offliner but it is my goal (as you can see in the roadmap) to make offliner fully compatible with serviceworkerware.

@delapuente
Copy link
Author

The quotes here are taken from this other thread.

It does, thanks for the context! The piece I guess I'm still missing is why the offliner implementation doesn't start using the new cache by default when the updated service worker is activated.

This is basically because I wanted the content to be in full control of the lifecycle. So, when service worker is activated, offliner dispatches an activationPending to the content but does not activate.

I understand that there can be some value to making this configurable, such that a client should be able to activate the updated service worker without starting to use the new cache (although I would still be interested to hear an explanation of the use case for this feature, as it isn't immediately clear to me).

But I don't understand the value in making this the default behavior. Wouldn't it make more sense for offliner to start using the new cache immediately unless the client has configured it to delay using the cache until an explicit call to activate?

The use case is that in desktop applications, in most of the cases, when a new version is available, the UX informs the user about it and provide a button to restart. I designed offliner with that in mind and now I realize it's not very webby. Maybe a more web-friendly approach would have been to provide the activation after reloading.

In defense of this default, I like the idea of leaving the decision to the content. It seems more homogeneous to me: the content always receives the activationPending and it opts to delay or not the activation limiting this way the configuration options keeping alignment with the code over configuration design principle. The activate on unload solution seems to work perfectly and the corner case of the browser crashing is totally recoverable.

Furthermore, the less offliner involves the developer into dealing with the actual service worker, the less he has to know about them. Remember one of the goals for offliner is to provide an abstraction layer for the service worker and only expose the lifecycle concepts.

As that developer, I would expect offliner to define a set of default behaviors while giving me the ability to configure it to behave differently. And regarding the question of when to start using a new cache, I would expect the default behavior to be that offliner starts using the new cache as soon as it activates the new worker, since that would be the common case, unless I configure it to delay using the new cache until I explicitly call activate.

I see your point and I promise I'm going to study how to implement it without affecting the current behaviour. Something like:

offliner.on('activationPending', function (event) {
  offliner.activateOnReload();
});

@delapuente
Copy link
Author

@dbialer only if you have time, do you mind to take a look at the roadmap for offliner to give me some feedback from the point of view of product, please? I find the feedback from @mykmelez very valuable as it forces me to re-think and transcript the technical reasoning behind offliner but another perspective would be very appreciated as well.

Thanks!

@mykmelez
Copy link
Contributor

mykmelez commented Nov 5, 2015

This is basically because I wanted the content to be in full control of the lifecycle. So, when service worker is activated, offliner dispatches an activationPending to the content but does not activate.

That isn't fuller control than offliner activating the updated service worker by default unless the app says otherwise. It's just a different default.

The use case is that in desktop applications, in most of the cases, when a new version is available, the UX informs the user about it and provide a button to restart. I designed offliner with that in mind and now I realize it's not very webby. Maybe a more web-friendly approach would have been to provide the activation after reloading.

This isn't a question of desktop vs. web. I've seen a variety of different update flows in desktop software, and this one is relatively rare in my experience. And there is plenty of desktop software that applies silent updates automatically, including Chrome, upon which the Service Worker lifecycle is based. Even when a desktop app does prompt the user to apply it (f.e. Telegram), restarting the app without confirming the prompt often applies the update automatically.

In any case, offliner provides both options, per its philosophy of giving the content total control. So the question is which behavior to make the default.

And the one that you've chosen is a footgun, given that it's different from the default behavior of Service Workers, while the API for offliner remains otherwise similar to the Service Worker API it abstracts.

It's also likely to be uncommon, even for apps that prompt the user to update them. If the user declines that prompt, most apps will still want to apply the update on reload. Making them specify that explicitly is requiring them to do more work.

The activate on unload solution seems to work perfectly and the corner case of the browser crashing is totally recoverable.

The risk here is twofold:

  1. That unload races service worker activation, with unclear consequences.
  2. That service worker activation delays unload.

Registering an unload listener also disables the bfcache. Besides regressing the performance of history navigation, that means that navigating away from the app (whether by clicking a link within the app or by entering another URL into the location bar) and then returning to it with the Back button will cause the app to update, which is unexpected. As a user, I expect the latest version of an app to open in a new tab. But I expect the current version of the app to appear when I click the Back button to return to it in an existing tab.

@delapuente
Copy link
Author

That isn't fuller control than offliner activating the updated service worker by default unless the app says otherwise. It's just a different default.

I think I don't get to explain myself. Sorry if it's confusing but I'll try again: the service worker is actually activated without the interaction of the user or client code. What we don't do is to start serving from the new cache without explicit permission from content (this is why offliner is dispatching a activationPending and waiting the client for calling .activate()).

If I opt for starting to serve contents from the new cache during the activate event, as the content can not delay the activation at all, it would start serving from the new cache without explicit permission (as the lifecycle of the service worker can be extended but not prevented). So, this default removes part of the control from the content.

And the one that you've chosen is a footgun, given that it's different from the default behavior of Service Workers, while the API for offliner remains otherwise similar to the Service Worker API it abstracts.

I don't think this is a footgun at all as it is very reasonable that the content receive a notification when there is a new version ready to be served. One the goals for offliner is to hide the service worker lifecylce completely (it's another story if you are interested in service worker internals) and provide an application lifecycle where the application (i.e the client code) is in charge of managing everything.

Sadly, I understand it feels like a footgun as the vocabulary chosen makes all the matters confuse as these discussions prove.

It's also likely to be uncommon, even for apps that prompt the user to update them. If the user declines that prompt, most apps will still want to apply the update on reload. Making them specify that explicitly is requiring them to do more work.

You're totally right here. I'm opening an issue right now to address this problem. It is not trivial because it affects the way offliner gets activated (as a service worker) but I'll try my best.

The risk here is twofold:

  1. That unload races service worker activation, with unclear consequences.
  2. That service worker activation delays unload.

AFAIK, per the spec, the activation should not race as the service worker simply awake when receiving the message event and swap the caches as its lifecycle is not tied to any particular page. And for 2, I'm not sure the service worker delays the unload as it's an asynchronous operation and again, unrelated with the content page lifecycle. Maybe it delays completely closing the browser but I would bet the delay is negligible. Even so, if this becomes a problem, I'll measure the impact.

@delapuente
Copy link
Author

@mykmelez I'm not sure we should continue the integration of offliner, at least, not for v1. I feel you don't rely on the software or maybe you think it is not enough mature an it makes totally sense. Indeed, it is not mature at all.

Furthermore, maybe oghliner does not want to automatize an application lifecycle but to provide a custom service worker what is something you mention here:

It'd also be interesting to look at a comparison of a basic offlining service worker developed from scratch versus one developed using offliner. (Apologies if this is already available and I just don't know about it!)

Maybe oghliner needs more control on pure service workers and not an abstraction.

@mykmelez mykmelez removed the backlog label Dec 2, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants