git ssb

1+

dinoworm ๐Ÿ› / catstack



Commit d257f1cb78aa333ab6399429df9d754ce4f561f5

universal app (server-side rendering)!

- use redux-simple-router instead of redux-router
- no more budo, just watchify and our static server (so no more live-reload for now)
- use helpers from https://github.com/jlongster/react-redux-universal-hot-example/
- add server-side renderer to stack
Michael Williams committed on 11/29/2015, 4:12:35 AM
Parent: 4cb19feb19f09ec24e9ab9ee78c7df9337ce2f68

Files changed

app/client.jschanged
app/reducers/index.jschanged
app/stack/index.jschanged
app/stack/render.jsadded
app/store.jschanged
app/assets/index.htmldeleted
app/util/fetch-all-data.jsadded
app/util/fetch-element.jsadded
package.jsonchanged
app/client.jsView
@@ -1,19 +1,38 @@
11 const React = require('react')
22 const { render } = require('react-dom')
3-const { createStore, applyMiddleware } = require('redux')
4-import { reduxReactRouter, routerStateReducer, ReduxRouter } from 'redux-router';
53 const { Provider } = require('react-redux')
6-const thunk = require('redux-thunk')
4+const { Router } = require('react-router')
5+const { createHistory } = require('history')
6+const { syncReduxAndRouter } = require('redux-simple-router')
77
8-const configureStore = require('app/store')
9-const { findTodos } = require('app/actions')
10-const Root = require('app/containers/root')
8+const routes = require('app/routes')
9+const createStore = require('app/store')
10+const fetchElement = require('app/util/fetch-element')
1111
12-const store = configureStore()
12+if (process.env.NODE_ENV === 'development') {
13+ var DevTools = require('app/components/dev-tools')
14+}
1315
14-//store.dispatch(getAllTodos())
16+const store = createStore(window.__data)
17+const history = createHistory()
1518
19+syncReduxAndRouter(history, store)
20+
21+const component = (
22+ <Router createElement={fetchElement} history={history}>
23+ { routes }
24+ </Router>
25+)
26+
1627 render(
17- <Root store={store} />,
28+ <Provider store={store} key="provider">
29+ <div>
30+ { component }
31+ {
32+ (process.env.NODE_ENV === 'development') ?
33+ <DevTools /> : null
34+ }
35+ </div>
36+ </Provider>,
1837 document.querySelector('main')
1938 )
app/reducers/index.jsView
@@ -1,8 +1,8 @@
11 const bulk = require('bulk-require')
22 const { combineReducers } = require('redux')
3-const { routerStateReducer } = require('redux-router')
3+const { routeReducer } = require('redux-simple-router')
44
55 module.exports = combineReducers({
66 ...bulk(__dirname, '!(index.js)'),
7- router: routerStateReducer
7+ routing: routeReducer
88 })
app/stack/index.jsView
@@ -2,9 +2,10 @@
22 const { mapObjIndexed, reduce, toPairs } = require('ramda')
33
44 const stackCreators = {
55 services: require('./services'),
6- static: require('./static')
6+ static: require('./static'),
7+ render: require('./render')
78 }
89
910 module.exports = createStack
1011
app/stack/render.jsView
@@ -1,0 +1,69 @@
1+// https://github.com/jlongster/react-redux-universal-hot-example/blob/master/src/server.js
2+
3+const React = require('react')
4+const { renderToString } = require('react-dom/server')
5+const { Provider } = require('react-redux')
6+const { createHistory } = require('history')
7+const { Router, RoutingContext, match } = require('react-router')
8+
9+const createStore = require('app/store')
10+const routes = require('app/routes')
11+const fetchAllData = require('app/util/fetch-all-data')
12+
13+module.exports = createRender
14+
15+function createRender (config) {
16+ return function render (req, res) {
17+ const store = createStore()
18+
19+ match({
20+ routes: routes,
21+ location: req.path
22+ }, function (err, redirectLocation, renderProps) {
23+ if (redirectLocation) {
24+ res.redirect(redirectLocation.pathname + redirectLocation.search)
25+ } else if (err) {
26+ res.status(500).send(err.message)
27+ } else if (!renderProps) {
28+ res.status(404).send('Not found')
29+ } else {
30+ fetchAllData(
31+ renderProps.components,
32+ store.getState, store.dispatch,
33+ renderProps.location,
34+ renderProps.params
35+ ).then(function () {
36+ const component = <Provider store={store} key="provider">
37+ <RoutingContext { ...renderProps } />
38+ </Provider>
39+
40+ const html = renderToString(component)
41+
42+ const fullHtml = renderFullPage(html, store.getState())
43+
44+ res.send(fullHtml)
45+ })
46+ }
47+ })
48+ }
49+}
50+
51+function renderFullPage (html, data) {
52+ return `
53+ <!DOCTYPE html>
54+ <html lang="en">
55+ <head>
56+ <meta charset="utf-8" />
57+ <title>Production TodoMVC</title>
58+ <meta name="viewport" content="width=device-width, initial-scale=1" />
59+ </head>
60+ <body>
61+ <main>${ html }</main>
62+ <script>
63+ window.__data = ${ JSON.stringify(data) }
64+ </script>
65+ <script src="bundle.js"></script>
66+ </body>
67+ </html>
68+ `
69+}
app/store.jsView
@@ -1,11 +1,9 @@
11 const { createStore, compose, applyMiddleware } = require('redux')
22 const thunk = require('redux-thunk')
3-const { reduxReactRouter } = require('redux-router')
43 const { createHistory } = require('history')
54
65 const reducer = require('app/reducers')
7-const routes = require('routes')
86
97 let storeEnhancers = []
108 let middleware = []
119
@@ -21,44 +19,28 @@
2119 storeEnhancers.push(
2220 applyMiddleware(...middleware)
2321 )
2422
25-storeEnhancers.push(
26- reduxReactRouter({
27- //routes,
28- createHistory
29- })
30-)
31-
3223 if (process.env.NODE_ENV === 'development') {
33-
3424 storeEnhancers.push(
3525 applyMiddleware(logger())
3626 )
3727 storeEnhancers.push(DevTools.instrument())
38- storeEnhancers.push(persistState(
39- window.location.href.match(
40- /[?&]debug_session=([^&]+)\b/
41- )
42- ))
28+
29+ if (module.browser) {
30+ storeEnhancers.push(persistState(
31+ window.location.href.match(
32+ /[?&]debug_session=([^&]+)\b/
33+ )
34+ ))
35+ }
4336 }
4437
4538 const createEnhancedStore = compose(
4639 ...storeEnhancers
4740 )(createStore)
4841
49-function configureStore(initialState) {
50- const store = createEnhancedStore(reducer, initialState)
51-
52- if (process.env.NODE_ENV === 'development') {
53- if (module.hot) {
54- module.hot.accept('app/reducers', () =>
55- store.replaceReducer(require('app/reducers'))
56- )
57- }
58- }
59-
60- return store
42+function finalCreateStore(initialState) {
43+ return createEnhancedStore(reducer, initialState)
6144 }
6245
63-module.exports = configureStore
64-
46+module.exports = finalCreateStore
app/assets/index.htmlView
@@ -1,12 +1,0 @@
1-<!DOCTYPE html>
2-<html lang="en">
3- <head>
4- <meta charset="utf-8" />
5- <title>Production TodoMVC</title>
6- <meta name="viewport" content="width=device-width, initial-scale=1" />
7- </head>
8- <body>
9- <main></main>
10- <script src="bundle.js"></script>
11- </body>
12-</html>
app/util/fetch-all-data.jsView
@@ -1,0 +1,17 @@
1+// https://github.com/jlongster/react-redux-universal-hot-example/blob/master/src/helpers/fetchAllData.js
2+
3+const Promise = require('pinkie-promise')
4+
5+module.exports = fetchAllData
6+
7+function fetchAllData(components, getState, dispatch, location, params) {
8+ const fetchers = components
9+ .filter((component) => !!component) // Weed out 'undefined' routes
10+ .filter((component) => component.fetchData) // only look at ones with a static fetchData()
11+ .map((component) => component.fetchData) // pull out fetch data methods
12+ .map(fetchData => {
13+ return fetchData(getState, dispatch, location, params)
14+ }) // call fetch data methods and return promises
15+
16+ return Promise.all(fetchers)
17+}
app/util/fetch-element.jsView
@@ -1,0 +1,14 @@
1+const React = require('react')
2+
3+module.exports = fetchElement
4+
5+function fetchElement (Component, props) {
6+ if (Component.fetchData) {
7+ Component.fetchData(
8+ store.getState, store.dispatch,
9+ props.location, props.params
10+ )
11+ }
12+ return React.createElement(Component, props)
13+}
14+
package.jsonView
@@ -9,11 +9,11 @@
99 "format": "snazzy --format",
1010 "test": "(npm run spec & npm run feature)",
1111 "spec": "node spec",
1212 "feature": "node feature",
13- "dev:client": "budo client --dir assets --serve bundle.js --live --pushstate -- -dv",
13+ "dev:client": "watchify client -o assets/bundle.js -dv",
1414 "dev:assets": "cpx \"app/assets/**/*\" assets -w",
15- "dev:server": "nodemon server",
15+ "dev:server": "node-dev server",
1616 "prod:client": "browserify client -o assets/bundle.js -g envify -g uglifyify",
1717 "prod:assets": "cpx \"app/assets/**/*\" assets",
1818 "prod:server": "node server",
1919 "dev": "NODE_ENV=development npm-run-all -p dev:*",
@@ -46,17 +46,17 @@
4646 "node": "^4.0.0",
4747 "npm": "^3.0.0"
4848 },
4949 "devDependencies": {
50- "budo": "^6.1.0",
5150 "cuke-tap": "^1.0.2",
5251 "jsdom": "^7.1.0",
53- "nodemon": "^1.8.1",
52+ "node-dev": "^2.7.1",
5453 "redux-devtools": "^3.0.0-beta-3",
5554 "redux-devtools-dock-monitor": "^1.0.0-beta-3",
5655 "redux-devtools-log-monitor": "^1.0.0-beta-3",
5756 "redux-logger": "^2.0.4",
58- "tape": "^4.2.2"
57+ "tape": "^4.2.2",
58+ "watchify": "^3.6.1"
5959 },
6060 "dependencies": {
6161 "babel-core": "^6.2.1",
6262 "babel-plugin-transform-object-rest-spread": "^6.1.18",
@@ -74,15 +74,16 @@
7474 "feathers": "^1.2.0",
7575 "history": "^1.13.1",
7676 "lnfs-cli": "^1.0.1",
7777 "npm-run-all": "^1.3.2",
78+ "pinkie-promise": "^2.0.0",
7879 "ramda": "^0.18.0",
7980 "react": "^0.14.3",
8081 "react-dom": "^0.14.3",
8182 "react-redux": "^4.0.0",
8283 "react-router": "^1.0.0",
8384 "redux": "^3.0.4",
84- "redux-router": "^1.0.0-beta5",
85+ "redux-simple-router": "0.0.10",
8586 "redux-thunk": "^1.0.0",
8687 "sheetify": "^3.1.0",
8788 "uglifyify": "^3.0.1"
8889 }

Built with git-ssb-web