-
Notifications
You must be signed in to change notification settings - Fork 330
Adds isomorphic/server-side React application-shell rendering #35
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
Changes from 9 commits
cd50242
584ac4f
2731fe5
96d4d9d
c55b325
6940401
a0de5ed
8a8fbd5
3a3e4ff
d7f6c52
16606c1
62b6b2c
bac1f38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
runtime: nodejs | ||
vm: true | ||
|
||
skip_files: | ||
- ^(.*/)?.*/node_modules/.*$ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,26 +9,33 @@ | |
"url": "http://github.com/insin/react-hn.git" | ||
}, | ||
"scripts": { | ||
"build": "npm run lint && cp node_modules/sw-toolbox/sw-toolbox.js public/sw-toolbox.js && nwb build && npm run precache", | ||
"lint": "eslint src", | ||
"lint:fix": "eslint --fix .", | ||
"start": "nwb serve", | ||
"precache": "sw-precache --root=public --config=sw-precache-config.json" | ||
"build": "npm run lint && cp node_modules/sw-toolbox/sw-toolbox.js public/sw-toolbox.js && ./node_modules/nwb/lib/bin/nwb.js build && npm run precache", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can replace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. Will update. |
||
"deploy": "gcloud preview app deploy", | ||
"lint": "./node_modules/eslint-config-jonnybuchanan/bin/lint.js src", | ||
"lint:fix": "./node_modules/eslint-config-jonnybuchanan/bin/lint.js --fix .", | ||
"start": "node server.js", | ||
"postinstall": "npm run build", | ||
"serve": "./node_modules/lib/bin/nwb.js serve", | ||
"precache": "./node_modules/sw-precache/cli.js --root=public --config=sw-precache-config.json" | ||
}, | ||
"engines": { | ||
"node": "6.1.0" | ||
}, | ||
"main": "server.js", | ||
"dependencies": { | ||
"ejs": "^2.4.1", | ||
"events": "1.1.0", | ||
"express": "^4.13.4", | ||
"firebase": "2.4.2", | ||
"firetruck.js": "0.1.1", | ||
"history": "2.1.1", | ||
"react": "15.0.2", | ||
"react-dom": "15.0.2", | ||
"react-router": "2.4.0", | ||
"react-timeago": "3.0.0", | ||
"reactfire": "0.7.0", | ||
"scroll-behavior": "0.5.0", | ||
"setimmediate": "1.0.4" | ||
}, | ||
"devDependencies": { | ||
"setimmediate": "1.0.4", | ||
"url-parse": "^1.1.1", | ||
"eslint-config-jonnybuchanan": "2.0.3", | ||
"nwb": "0.8.1", | ||
"sw-precache": "^3.1.1", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
var express = require('express') | ||
var React = require('react') | ||
var renderToString = require('react-dom/server').renderToString | ||
var ReactRouter = require('react-router') | ||
|
||
require('babel/register') | ||
var routes = require('./src/routes') | ||
|
||
var app = express() | ||
app.set('view engine', 'ejs') | ||
app.set('views', process.cwd() + '/src/views') | ||
app.set('port', (process.env.PORT || 5000)) | ||
app.use(express.static('public')) | ||
|
||
app.get('*', function(req, res) { | ||
ReactRouter.match({ | ||
routes: routes, | ||
location: req.url | ||
}, function(err, redirectLocation, props) { | ||
if (err) { | ||
res.status(500).send(err.message) | ||
} | ||
else if (redirectLocation) { | ||
res.redirect(302, redirectLocation.pathname + redirectLocation.search) | ||
} | ||
else if (props) { | ||
var markup = renderToString( | ||
React.createElement(ReactRouter.RouterContext, props, null) | ||
) | ||
res.render('index', { markup: markup }) | ||
} | ||
else { | ||
res.sendStatus(404) | ||
} | ||
}) | ||
}) | ||
|
||
app.listen(app.get('port'), function(err) { | ||
if (err) { | ||
console.log(err) | ||
return | ||
} | ||
console.log('Running app at localhost:' + app.get('port')) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,7 +35,7 @@ var Stories = React.createClass({ | |
} | ||
}, | ||
|
||
componentWillMount() { | ||
componentDidMount() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. more out of interest, but why is this required? Is this what gets around that weird React error I was getting? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, of course. |
||
setTitle(this.props.title) | ||
this.store = new StoryStore(this.props.type) | ||
this.store.addListener('update', this.handleUpdate) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,14 @@ | ||
module.exports = { | ||
get(key, defaultValue) { | ||
var value = window.localStorage[key] | ||
return (typeof value != 'undefined' ? value : defaultValue) | ||
if (typeof window !== 'undefined') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updating to reflect feedback in just a sec. |
||
var value = window.localStorage[key] | ||
return (typeof value != 'undefined' ? value : defaultValue) | ||
} | ||
}, | ||
set(key, value) { | ||
window.localStorage[key] = value | ||
if (typeof window !== 'undefined') { | ||
window.localStorage[key] = value | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
<meta charset="utf-8"> | ||
<title>React HN</title> | ||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
|
||
<link rel="manifest" href="manifest.json"> | ||
<meta name="theme-color" content="#222222"> | ||
|
||
<link rel="shortcut icon" href="img/favicon.ico"> | ||
<link rel="apple-touch-icon" sizes="57x57" href="img/apple-touch-icon-57x57.png"> | ||
<link rel="apple-touch-icon" sizes="60x60" href="img/apple-touch-icon-60x60.png"> | ||
<link rel="apple-touch-icon" sizes="72x72" href="img/apple-touch-icon-72x72.png"> | ||
<link rel="apple-touch-icon" sizes="76x76" href="img/apple-touch-icon-76x76.png"> | ||
<link rel="apple-touch-icon" sizes="114x114" href="img/apple-touch-icon-114x114.png"> | ||
<link rel="apple-touch-icon" sizes="120x120" href="img/apple-touch-icon-120x120.png"> | ||
<link rel="apple-touch-icon" sizes="144x144" href="img/apple-touch-icon-144x144.png"> | ||
<link rel="apple-touch-icon" sizes="152x152" href="img/apple-touch-icon-152x152.png"> | ||
<link rel="apple-touch-icon" sizes="180x180" href="img/apple-touch-icon-180x180.png"> | ||
<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32"> | ||
<link rel="icon" type="image/png" href="img/android-chrome-192x192.png" sizes="192x192"> | ||
<link rel="icon" type="image/png" href="img/favicon-96x96.png" sizes="96x96"> | ||
<link rel="icon" type="image/png" href="img/favicon-16x16.png" sizes="16x16"> | ||
<link rel="mask-icon" href="img/safari-pinned-tab.svg" color="#222222"> | ||
|
||
<meta name="msapplication-TileColor" content="#222222"> | ||
<meta name="msapplication-TileImage" content="img/mstile-144x144.png"> | ||
<meta name="msapplication-config" content="img/browserconfig.xml"> | ||
|
||
<link rel="stylesheet" href="css/style.css"> | ||
</head> | ||
<body> | ||
<div id="app"><%- markup %></div> | ||
<script src="build/vendor.js"></script> | ||
<script src="build/app.js"></script> | ||
<script> | ||
if ('serviceWorker' in navigator) { | ||
navigator.serviceWorker.register('./service-worker.js', { | ||
scope: './' | ||
}) | ||
.then(function(registration) { | ||
registration.onupdatefound = function() { | ||
if (navigator.serviceWorker.controller) { | ||
var installingWorker = registration.installing; | ||
|
||
installingWorker.onstatechange = function() { | ||
switch (installingWorker.state) { | ||
case 'installed': | ||
break; | ||
case 'redundant': | ||
throw new Error('The installing ' + | ||
'service worker became redundant.'); | ||
default: | ||
// Ignore | ||
} | ||
}; | ||
} | ||
}; | ||
}).catch(function(e) { | ||
console.error('Error during service worker registration:', e); | ||
}); | ||
} else { | ||
console.log('service worker is not supported'); | ||
} | ||
</script> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this come with any predefined environment variables?
If not, setting
NODE_ENV
toproduction
will make Express cache the view templateThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. It looks like GAE does support environment variables: https://cloud.google.com/appengine/docs/flexible/nodejs/configuring-your-app-with-app-yaml#Node.js_app_yaml_Defining_environment_variables. I'll update.