{"action":"created","issue":{"url":"https://api.github.com/repos/insin/react-hn/issues/47","repository_url":"https://api.github.com/repos/insin/react-hn","labels_url":"https://api.github.com/repos/insin/react-hn/issues/47/labels{/name}","comments_url":"https://api.github.com/repos/insin/react-hn/issues/47/comments","events_url":"https://api.github.com/repos/insin/react-hn/issues/47/events","html_url":"https://github.com/insin/react-hn/pull/47","id":159407133,"number":47,"title":"Add support for server-side rendering Top Stories & Comments","user":{"login":"addyosmani","id":110953,"avatar_url":"https://avatars.githubusercontent.com/u/110953?v=3","gravatar_id":"","url":"https://api.github.com/users/addyosmani","html_url":"https://github.com/addyosmani","followers_url":"https://api.github.com/users/addyosmani/followers","following_url":"https://api.github.com/users/addyosmani/following{/other_user}","gists_url":"https://api.github.com/users/addyosmani/gists{/gist_id}","starred_url":"https://api.github.com/users/addyosmani/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/addyosmani/subscriptions","organizations_url":"https://api.github.com/users/addyosmani/orgs","repos_url":"https://api.github.com/users/addyosmani/repos","events_url":"https://api.github.com/users/addyosmani/events{/privacy}","received_events_url":"https://api.github.com/users/addyosmani/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":{"login":"insin","id":226692,"avatar_url":"https://avatars.githubusercontent.com/u/226692?v=3","gravatar_id":"","url":"https://api.github.com/users/insin","html_url":"https://github.com/insin","followers_url":"https://api.github.com/users/insin/followers","following_url":"https://api.github.com/users/insin/following{/other_user}","gists_url":"https://api.github.com/users/insin/gists{/gist_id}","starred_url":"https://api.github.com/users/insin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/insin/subscriptions","organizations_url":"https://api.github.com/users/insin/orgs","repos_url":"https://api.github.com/users/insin/repos","events_url":"https://api.github.com/users/insin/events{/privacy}","received_events_url":"https://api.github.com/users/insin/received_events","type":"User","site_admin":false},"milestone":null,"comments":7,"created_at":"2016-06-09T13:24:57Z","updated_at":"2016-06-19T14:55:05Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/insin/react-hn/pulls/47","html_url":"https://github.com/insin/react-hn/pull/47","diff_url":"https://github.com/insin/react-hn/pull/47.diff","patch_url":"https://github.com/insin/react-hn/pull/47.patch"},"body":"**Please don't merge in just yet. This work requires some discussion about the UX**\r\n\r\nThis set of changes adds server-side rendering for both Top Stories (index) and comment threads. It enables React HN to deliver content quickly, especially useful for flakey/slow networks or where our vendor/app bundle hasn't been fully loaded yet (sometimes a few seconds on slow connections). It works with JavaScript disabled too.\r\n\r\nDemo: https://react-hn-ssr.appspot.com\r\nVideo: https://www.youtube.com/watch?v=E1YNRc3Kfag&feature=youtu.be\r\n[Lighthouse](https://github.com/GoogleChrome/lighthouse/) scores: 100/100\r\n\r\n## How\r\n\r\nI investigated a few different ways SSR could be added over in #27. The approach I landed on moves most of the work over into Express, with minimal changes to our React code to support 'preboot' data and hydration. We populate the view in `componentWillMount` (server/client) and hydrate in `componentDidMount` (client).  \r\n\r\nOriginally, I tried to do full server-side rendering using the Firebase SDK. This involved a large number of network requests to be resolved for stories and comments, which ended up taking anywhere up to a minute. In a normal server environment, we would start adding in a caching layer here to avoid each visit having to incur this cost. \r\n\r\nThankfully, there exists a third-party (unofficial) Hacker News API we can call, which does support caching and provides story and comment data in a slightly more friendly format. Because the data format is different enough to what we currently rely on in the rest of our React components (in particular, our templates), I decided to replicate the output in EJS templates allowing us to get the same look and feel once output. \r\n\r\n## Some screenshots from WebPageTest\r\n\r\nFirst meaningful paint happening at 0.6s on cable with SSR compared to 2.1s with our current build:\r\n\r\n![screen shot 2016-06-09 at 14 30 41](https://cloud.githubusercontent.com/assets/110953/15931259/e3700592-2e4e-11e6-8ffe-63676266e31d.png)\r\n\r\nHydration to real-time content, occurring at roughly the same time as our current build:\r\n\r\n![screen shot 2016-06-09 at 14 32 15](https://cloud.githubusercontent.com/assets/110953/15931285/07cfa4ce-2e4f-11e6-9af0-2b182f466e4d.png)\r\n\r\nhttp://www.webpagetest.org/video/compare.php?tests=160609_TS_1H8W,160609_SD_1H8Y if you'd like to look at the data directly.\r\n\r\n## UX\r\n\r\nPerhaps the biggest change this PR adds is a change to the ReactHN UX. If you navigate to the demo with JS off/on a throttled connection, content will load/display quickly and eventually 'update' to real-time. On a fast connection, you'll see the server-rendered content and then very shortly after the hydrated real-time experience. It's a little like FOUC. This only happens for the first page of top story results (after which the experience is per usual), however I'm interested in hearing what others think about the experience. Is it okay? Does it feel unnatural? If the latter, there are a few options we have, such as delaying hydration until a future time (based on an interval). Alternative ideas are also welcome.\r\n"},"comment":{"url":"https://api.github.com/repos/insin/react-hn/issues/comments/227001519","html_url":"https://github.com/insin/react-hn/pull/47#issuecomment-227001519","issue_url":"https://api.github.com/repos/insin/react-hn/issues/47","id":227001519,"user":{"login":"addyosmani","id":110953,"avatar_url":"https://avatars.githubusercontent.com/u/110953?v=3","gravatar_id":"","url":"https://api.github.com/users/addyosmani","html_url":"https://github.com/addyosmani","followers_url":"https://api.github.com/users/addyosmani/followers","following_url":"https://api.github.com/users/addyosmani/following{/other_user}","gists_url":"https://api.github.com/users/addyosmani/gists{/gist_id}","starred_url":"https://api.github.com/users/addyosmani/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/addyosmani/subscriptions","organizations_url":"https://api.github.com/users/addyosmani/orgs","repos_url":"https://api.github.com/users/addyosmani/repos","events_url":"https://api.github.com/users/addyosmani/events{/privacy}","received_events_url":"https://api.github.com/users/addyosmani/received_events","type":"User","site_admin":false},"created_at":"2016-06-19T14:55:05Z","updated_at":"2016-06-19T14:55:05Z","body":"I've updated the implementation to only display the change in UX for the first page of top story results. As soon as the ReactHN React bundle gets loaded and we switch to client-side routing, everything works the same as it did before. Video: http://recordit.co/vPho97mZCn"}}
{"actor":{"display_login":"addyosmani"}}