diff --git a/hn-server-fetch.js b/hn-server-fetch.js index 3872e61..7d20e81 100644 --- a/hn-server-fetch.js +++ b/hn-server-fetch.js @@ -4,14 +4,14 @@ require('isomorphic-fetch') The official Firebase API (https://github.com/HackerNews/API) requires multiple network connections to be made in order to fetch the list of Top Stories (indices) and then the summary content of these stories. Directly requesting these resources makes server-side -rendering cumbersome as it is slow and ultimately requires that you maintain your own -cache to ensure full server renders are efficient. +rendering cumbersome as it is slow and ultimately requires that you maintain your own +cache to ensure full server renders are efficient. To work around this problem, we can use one of the unofficial Hacker News APIs, specifically -https://github.com/cheeaun/node-hnapi which directly returns the Top Stories and can cache +https://github.com/cheeaun/node-hnapi which directly returns the Top Stories and can cache responses for 10 minutes. In ReactHN, we can use the unofficial API for a static server-side -render and then 'hydrate' this once our components have mounted to display the real-time -experience. +render and then 'hydrate' this once our components have mounted to display the real-time +experience. The benefit of this is clients loading up the app that are on flakey networks (or lie-fi) can still get a fast render of content before the rest of our JavaScript bundle is loaded. @@ -21,53 +21,53 @@ can still get a fast render of content before the rest of our JavaScript bundle * Fetch top stories */ exports.fetchNews = function(page) { - page = page || '' - return fetch('http://node-hnapi.herokuapp.com/news' + page).then(function(response) { - return response.json() - }).then(function(json) { - var stories = '
    ' - json.forEach(function(data, index) { - var story = '
  1. ' + - '
    ' + data.title + ' ' + - '(' + data.domain + ')
    ' + - '
    ' + data.points + ' points ' + - 'by ' + data.user + ' ' + - ' | ' + - '' + data.comments_count + ' comments
    ' - '
  2. ' - stories += story - }) - stories += '
' - return stories - }) + page = page || '' + return fetch('http://node-hnapi.herokuapp.com/news' + page).then(function(response) { + return response.json() + }).then(function(json) { + var stories = '
    ' + json.forEach(function(data, index) { + var story = '
  1. ' + + '
    ' + data.title + ' ' + + '(' + data.domain + ')
    ' + + '
    ' + data.points + ' points ' + + 'by ' + data.user + ' ' + + ' | ' + + '' + data.comments_count + ' comments
    ' + '
  2. ' + stories += story + }) + stories += '
' + return stories + }) } function renderNestedComment(data) { - return '
' + - '
' + - '
' + - '
[–] ' + - '' + data.user + ' ' + - ' ' + - 'link
' + - '
' + - '
' + data.content +'
' + - '

reply

' + - '
' + - '
' + - '
' + - '
' + return '
' + + '
' + + '
' + + '
[–] ' + + '' + data.user + ' ' + + ' ' + + 'link
' + + '
' + + '
' + data.content +'
' + + '

reply

' + + '
' + + '
' + + '
' + + '
' } function generateNestedCommentString(data) { - var output = '' - data.comments.forEach(function(comment) { - output+= renderNestedComment(comment) - if (comment.comments) { - output+= generateNestedCommentString(comment) - } - }) - return output + var output = '' + data.comments.forEach(function(comment) { + output+= renderNestedComment(comment) + if (comment.comments) { + output+= generateNestedCommentString(comment) + } + }) + return output } /** @@ -75,26 +75,26 @@ function generateNestedCommentString(data) { * TODO: Add article summary at top of nested comment thread */ exports.fetchItem = function(itemId) { - return fetch('https://node-hnapi.herokuapp.com/item/' + itemId).then(function(response) { - return response.json() - }).then(function(json) { - var comments = '' - json.comments.forEach(function(data, index) { - var comment = '
' + - '
' + - '
' + - '
[–] ' + - '' + data.user + ' ' + - ' ' + - 'link
' + - '
' + - '
' + data.content +'
' + - '

reply

' + - '
' + - '
' + - '
' - comments += generateNestedCommentString(data) + '
' + comment - }) - return comments - }) + return fetch('https://node-hnapi.herokuapp.com/item/' + itemId).then(function(response) { + return response.json() + }).then(function(json) { + var comments = '' + json.comments.forEach(function(data, index) { + var comment = '
' + + '
' + + '
' + + '
[–] ' + + '' + data.user + ' ' + + ' ' + + 'link
' + + '
' + + '
' + data.content +'
' + + '

reply

' + + '
' + + '
' + + '
' + comments += generateNestedCommentString(data) + '
' + comment + }) + return comments + }) } \ No newline at end of file diff --git a/nwb.config.js b/nwb.config.js index c723916..ad8dedb 100644 --- a/nwb.config.js +++ b/nwb.config.js @@ -26,13 +26,13 @@ module.exports = { names: ['core'], filename: '[name].js', minChunks: Infinity - }), + }), new HtmlWebpackPlugin({ filename: 'views/index.ejs', template: 'src/views/index.ejs', markup: '
<%- markup %>
' }) ] - } + } } } \ No newline at end of file diff --git a/public/index-static.html b/public/index-static.html index 61988d4..bc38e46 100644 --- a/public/index-static.html +++ b/public/index-static.html @@ -4,7 +4,7 @@ React HN - + @@ -25,11 +25,11 @@ - + - + diff --git a/server.js b/server.js index 9f84310..fdd04f2 100644 --- a/server.js +++ b/server.js @@ -52,7 +52,7 @@ app.get('/news/story/:id', function (req, res, next) { res.render('index', { markup: markup }) }) } - }) + }) }); app.get('*', function(req, res) { @@ -68,7 +68,7 @@ app.get('*', function(req, res) { } else if (props) { var markup = renderToString(React.createElement(ReactRouter.RouterContext, props, null)) - res.render('index', { markup: markup }) + res.render('index', { markup: markup }) } else { res.sendStatus(404) diff --git a/src/views/index.ejs b/src/views/index.ejs index 5dcc37f..a6d01f4 100644 --- a/src/views/index.ejs +++ b/src/views/index.ejs @@ -4,7 +4,7 @@ React HN - + @@ -25,7 +25,7 @@ - + @@ -71,6 +71,6 @@ ga('send', 'pageview'); - +