devpunks/snuggsi

Progressive Web Apps Checklist

Closed this issue · 10 comments

I feel like I should have never looked at this @brandondees @tmornini.

Seems to be the "Gold Standard" these days.

References

Checklist

We actually pass this one with flying colors. 1.8s (simulated) for FULL CONTENT load (all pages no images) And still not utilizing HTTP/2 server push nor <link rel=preload/prefetch> yet. Nor preloading web fonts (which still are the most expensive request we are making)

See Comments: https://github.com/devpunks/snuggsi/blob/master/index.html#L6-L44

capture d ecran 2017-07-01 a 00 50 29

3G Network (Throttled)

capture d ecran 2017-07-01 a 00 53 28

Normal (Throttling Disabled)

capture d ecran 2017-07-01 a 00 59 10

NICE!

yeah i do see snuggsi being sold as a tool for achieving these goals more easily for regular apps. the script load/parse time for the big frameworks are fairly substantial and well, the whole point is folks want to add their code on top of that, so it's valuable to give them as much headroom as possible.

speaking of caching, preloading resources, etc. i want to see some attempt made (and maybe i'll work on it myself) to replicate [the snuggsi way] the kinds of "for free" enhancements that a tool like Turbolinks provides without having to really invest significant dev time/effort/learning. the point about navigation being instantly UI-responsive even if it means displaying a transition or loading animation while it actually happens, is one of those substantial UX things that a general-use component(s) could make easy to drop in without having to re-engineer anything else. intercept click/activate events on hrefs and decorate the behavior by using the modern APIS including history, page replacement (in multiple stages), and fetch. turbolinks does this but the delivery falls a little short of the marketing promise, and the time may have come for a better, faster, closer-to-the-specs way of doing those types of things.

the time may have come for a better, faster, closer-to-the-specs way of doing those types of things

It's always the time for that sort of thing. (AKA progress!)

@brandondees should check out <nav-view> (https://snuggsi.herokuapp.com/examples/nav-view/example.html). @Robertchristopher and I did some nice work on it. @albertoponti and I are already using it on a personal project. I'd say only thing it's missing is loading each <main view> from a <link rel=import> "Holy Grail". What I like about this component is any "section" can toggle the visibility of the content instead of hot swapping the document.body and document.title as Turbolinks does (which we already do in <nav-view> ). This is more akin to <layer src=...> from the bad old days of Netscape. Since we are merely using the Fragment Identifier the :target CSS pseudo selector and Element.hidden Global Attribute we actually are merely causing a repaint not a reflow. The "pages" switch in double digit μ MICROSECONDS. Progressive enhancement therefore in old browsers would just be traditional ⚓️ anchor link functionality based around the <main id=fragmentid>. Cute trick using an ancient standard that's been around since IE5.5

Source code

https://github.com/devpunks/snuggsi/blob/master/examples/nav-view

Performance of <main view> Visibility Change

capture d ecran 2017-07-01 a 14 34 34

/cc @tmornini @robcole @mrbernnz @lukemelia @btakita @scottmacdowell

TL;DR; $.ready() came back to haunt us... or: Figuring out when the document is loaded sucks with a polyfill

@brandondees speaking of which there is a funky section of the code in <nav-view>. The problem is evergreen browsers act just as we would expect. And that is the "imported" <nav-view> is available immediately as the page is parsed and import is loaded (which happens pretty quickly). We wait until DOMContentLoaded to trigger <nav-view> obviously because any Element can be a view up until the closing </body> tag so we must wait until then. I'm not sure what's going on but seems like for browsers that need the polyfill for HTML Imports (i.e. Firefox) there's some awkward permutation of the event loading strategy. Has actually been a thorn in this library's side.

Whatever solution we come up with we may want to upstream into the core library. I feel this will come up again and again. Especially with custom elements that need to interact with the entire document body. (Not typical but expected as in your case @brandondees)

Any thoughts would be appreciated because this effects EVERY custom element due to the fact any one of them can potentially "imported" from a remote source into the master document.

  initialize () {

    /comp|inter|loaded/.test (document.readyState)
       // Classic browsers: custom element is upgraded via polyfill
       // AFTER load (which by this time has already occurred).
       // explicitly trigger event handler
      ? this.onload (/* where is the event? this is smelly */)
       // Evergreen browsers: custom element is "upgraded"
       // from platform before DOMContentLoaded
       // register `onload` handler to fire later in time
      : document.addEventListener
          ('DOMContentLoaded', this.onload)
  }

  onload (event) {
    /* do some stuff when the Document is ready (but not loaded. bad name?) */
    this.render () // Force repaint.
  }

Taken from https://github.com/devpunks/snuggsi/blob/master/examples/nav-view/index.es#L5-L13

suppose we want a version that does content replacement rather than toggling visibility... can this same component support that or would it require a different one? my thinking is that for sites that have a lot of content per page, navigating between lots of them by visibility toggling could become problematic in terms of memory consumption (the bane of browser users on affordable systems everywhere), or even CPU consumption in cases where there might be for example some background animation burning up GPU/CPU outside of requestAnimationFrame().

this effectively just replicates the "css tabs via radio buttons" technique but more cleanly, if i understand it correctly.

i'm not sure i'm even up for getting that deep with the browser document lifecycle events. maybe look for a possible workaround in the way that other tools like turbolinks handle the equivalent problem.

also, to be clear, it's totally fine to potentially just not fully support the laggard browsers, especially if they're the less popular ones, as long as there's some kind of progressive enhancement / graceful degradation strategy in place for those. i think in the case of imports, we gotta have some kind of working polyfill for FF, but if it's a question of handling a no-js environment or some legacy browser with wonky document lifecycle events, maybe just design components to have some kind of fallback behavior for those situations.

@brandondees perhaps the following for partial importing. @tmornini and i had a lengthy convo on the topic a little while ago. If you agree please help out and round up an issue and i'll bang it out. We can curb this convo there and get back to the issue at hand (Pun intended) These ☑️ Web ☑️ performance ☑️ checklists ☑️ ain't ☑️ gonna ☑️ check ☑️ themselves! /cc

<link rel=import href=nav-view>
<link rel=import href=main-view>

<nav-view />

<main-view href=home.html>
<!-- all your kewl HTMLz will show up here -->
</main-view>

DO REMEMBER HTML is declarative not imperative. That url can be used to preload/prefecth "behind the scenes" since no network hit will occur. We're just calling it href because src didn't feel right and can't think of a better attribute name. so theoretically this <main-view> could actually use it's href= as merely a "reference" to the (partial) resource by URL.

Wait a minute...I think the whole "hypermedia" part of the web just clicked.

@cristhiandick @albertoponti please review this.