Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preload data bundles for snappy client transitions #74

Merged
merged 12 commits into from Apr 6, 2016

Conversation

gigabo
Copy link
Contributor

@gigabo gigabo commented Apr 5, 2016

Adds a method to preload data for a URL that might be navigated to via client transition.

ReactServerAgent.preloadDataForUrl(url);

The data is then cached for the lifetime of the client controller. If a client transition is made to url then the ReactServerAgent cache is pre-populated.

A new page lifecycle was added to provide bundles of preloaded data. It just runs handleRoute, waits for data to resolve, and then spits out the RSA cache as a JSON blob. It's triggered by a query-string parameter.

TODO: Invalidation. Probably need a method to blow away the preload cache. Maybe also one to drop data for individual URLs.

@@ -10,8 +11,14 @@ function makeRequest (method, url) {
return new Request(method, url, API.cache());
}

const BUNDLE_CACHE = {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nitpicky thought: we currently use "bundle" to talk about the static JS bundles, so maybe its worth using a different term here, or a more specific one like DATA_BUNDLE_CACHE.

As always, feel free to ignore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @aickin, I've pushed a patch that uses DATA_BUNDLE to disambiguate.

Just "bundle" is ambiguous since we also use webpack JS bundles.
Eliminate a duplicate magic string
@aickin
Copy link
Contributor

aickin commented Apr 5, 2016

This is an absurdly elegant way to deal with bundling and preloading data. @roblg mentioned the bundling to me the other night and I was blown away. Bravo.

One thought, perhaps parallel to this PR: I wonder if it's also worthwhile to write some code that allows the pre-loading of the JavaScript and CSS bundles, which are the other potentially significant drivers of latency. It seems to that this solution will be awesome when going from one page of a particular type to another of the same type (like LDP --> LDP), but less so when switching types. I could imagine it just using the built-in browser prefetch, which currently works in about 2/3rds of browsers. Thoughts?

@gigabo
Copy link
Contributor Author

gigabo commented Apr 5, 2016

pre-loading of the JavaScript and CSS bundles

Ooh, yeah! 🚀

Let's see... For the JS bundle webpack will fetch it for us (and get it all prepped) if we call the loader in the routes object.

For CSS, unfortunately, I'm not sure if we can cheaply preload since the URLs are returned from getHeadStylesheets and it's not safe to call page methods out of order.

Good idea!

@aickin
Copy link
Contributor

aickin commented Apr 5, 2016

Hmmm... good point. You don't want to call handleRoute on the client; that kind of defeats the entire purpose.

Here's a wacky idea: could you call getHeadStylesheets and getScripts (or whatever it's called) on the server side and pass the JS/CSS URLs down in the JSON with the data? Then you could add <link rel="prefetch"> for each resource immediately, with the hope that the browser will download them before the user navigates. This would also help in the situation where a needed JS file isn't part of the page bundle (e.g. third party scripts), which the webpack loader will not be able to prefetch.

One downside with this idea vs. your current solution is that you'd need to parse the JSON from the server when it's downloaded, rather than when it's needed, which I really like about the current solution. If that was really a problem in practice, you could conceivably make some easier-to-parse format.

@gigabo
Copy link
Contributor Author

gigabo commented Apr 6, 2016

@aickin - That's perfect!

I'm going to freeze the scope of this PR to try to get some 👍 s and get it merged. Filed #77 to capture JS and CSS asset prefetch as the next step for client transition performance improvement.

@aickin
Copy link
Contributor

aickin commented Apr 6, 2016

Sounds great. Thanks!

And fwiw, this PR lgtm (am I even allowed to say that?).

@bartkusa
Copy link

bartkusa commented Apr 6, 2016

As an aside, <link rel="prefetch"> is/was kinda bad in Chrome. Last time I looked (a year ago?), it took priority over the current page's requests, like images.

Just check Chromium's bug tracker before forging ahead.

@aickin
Copy link
Contributor

aickin commented Apr 6, 2016

Do you have a citation for when that was true? At least according to this presentation by Ilya Grigorik, at least, prefetch hints "have lowest possible priority".

@@ -10,8 +11,14 @@ function makeRequest (method, url) {
return new Request(method, url, API.cache());
}

const DATA_BUNDLE_CACHE = {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still trying to read through this PR, but this looks like a module-level variable? Does it have request-specific stuff in it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. Can't preload server-side. Still, this variable as a global gives me the heebie-jeebies. Can we add a comment here to that effect as well? I literally almost had a heart attack....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh. Good call. Pushed a patch that both adds a comment and also just makes DATA_BUNDLE_CACHE undefined on the server.

Want to be extra sure that we don't accidentally cache data across requests on
the server.
@bartkusa
Copy link

bartkusa commented Apr 6, 2016

https://code.google.com/p/chromium/issues/detail?id=61476

(Maybe this is a bug in Webkit but not in Blink?)
(Maybe we should move this conversation to an Issue instead of yammering in this PR?)

@roblg
Copy link
Member

roblg commented Apr 6, 2016

LGTM 👍

And FWIW, @aickin you have my vote to be allowed to say "lgtm" ;)

@gigabo
Copy link
Contributor Author

gigabo commented Apr 6, 2016

And FWIW, @aickin you have my vote to be allowed to say "lgtm" ;)

Agreed. Thanks for reviewing!

@aickin
Copy link
Contributor

aickin commented Apr 6, 2016

@bartkusa Thanks for the warning and the cite!

@gigabo & @roblg Aw shucks, thanks!

We access it in a few places, but we don't want to be able to _write_ to it.
@gigabo gigabo merged commit 3cc1cab into redfin:master Apr 6, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants