ember-fastboot / fastboot-app-server

A production-ready app server for running Ember FastBoot apps
140 stars 72 forks source link

Chrome tab restore breaks app #107

Open davewasmer opened 5 years ago

davewasmer commented 5 years ago

It appears that Chrome's "restore tab" feature breaks Fastboot apps hosted by fastboot-app-server.

It looks like Chrome's restore feature pulls a cached copy of the page HTML when it restores the tab (probably to speed up the restore). The problem appears when you close Chrome, deploy a new version of the app, and the open Chrome and restore the tab. The restored tab uses the cached HTML, meaning it points to the old asset fingerprints. But those assets are no longer being served by fastboot-app-server, meaning those requests fail. The result is a broken app load: you get all the HTML, but the CSS and JS assets fail to load.

Normally, for non-Fastboot apps hosted on something like S3, we'd usually just keep the old assets for old deploys lying around. Which means whenever you'd get this situation, the old assets would successfully load and the app would work (albeit running the old deploy). Whenever the user refreshed, they would get a fresh copy of index.html that points to the new asset fingerprints, and everything would be fine.

However, because fastboot-app-server apparently doesn't serve up assets from previous deploys, this breaks.

I imagine the ideal solution here would be to keep assets from previous deploys around (probably configurable by time, i.e. keep for X hours/days). We wouldn't need to keep workers running for those old versions, since the cache restore just wants the assets.

davewasmer commented 5 years ago

I suppose another option would be to treat this as a downstream problem, and recommend that you put a caching layer in front of Fastboot which you could configure to cache the fingerprinted assets for as long as you wanted.

courthead commented 5 years ago

You might want new visitors to always get the freshest version of the site. In that case, you can detect when a user is attempting to load an old static file, because the file will fail to load. For example…

<script src="{{rootURL}}assets/vendor.js" onerror="window.getFreshPage()></script>

Then your getFreshPage function can simply reload the page with a unique query string appended to it, so it'll miss the cache.

davewasmer commented 5 years ago

@courthead appreciate the tip, didn’t know about onerror!

The query param solution feels a bit iffy though - potential collisions with in app qp’s for example.

FWIW, we ended up going with a downstream CDN cache that caches fingerprinted assets indefinitely. Seems to be working so far!