git ssb

1+

dinoworm ๐Ÿ› / catstack



Commit 8d668726e7d11fcdfc803f3c47ed305680c7194f

split server into micro-services!

each service will now reload independently in development, should be much faster. also will allow us to create a legit production deploy using docker-compose.

also i really like the consistency of using npm scripts to start each service.
Michael Williams committed on 1/3/2016, 3:14:24 AM
Parent: d393015f835e882e9ded1efb5f5b459f624ee943

Files changed

app/api.jschanged
app/package.jsonchanged
app/stack/services.jschanged
app/stack/render.jsdeleted
app/stack/static.jsdeleted
app/client.jsdeleted
app/render-browser.jsadded
app/server.jsdeleted
app/render.jsadded
app/static.jsadded
config/index.jschanged
package.jsonchanged
api.jsadded
client.jsdeleted
server.jsdeleted
render.jsadded
static.jsadded
app/api.jsView
@@ -1,0 +1,21 @@
1+const feathers = require('feathers')
2+const { mapObjIndexed, reduce, toPairs } = require('ramda')
3+
4+const services = require('app/services')
5+const config = require('app/config')
6+
7+module.exports = createServer
8+
9+function createServer (config) {
10+ const app = feathers()
11+
12+ useAll(app, services)
13+
14+ return app
15+}
16+
17+function useAll (app, services) {
18+ return reduce((app, [name, service]) => {
19+ return app.use(`/${name}`, service)
20+ }, app, toPairs(services))
21+}
app/package.jsonView
@@ -1,7 +1,8 @@
11 {
22 "browser": {
3- "./api.js": "./clients/index.js"
3+ "./render.js": "./render-browser.js",
4+ "./api.js": "./api-browser.js"
45 },
56 "browserify": {
67 "transform": [
78 ["cssify", { "modules": true } ],
app/stack/services.jsView
@@ -1,21 +1,0 @@
1-const feathers = require('feathers')
2-const { mapObjIndexed, reduce, toPairs } = require('ramda')
3-
4-const services = require('app/services')
5-
6-module.exports = createServices
7-
8-function createServices(config) {
9- const app = feathers()
10-
11- useAll(app, services)
12-
13- return app
14-}
15-
16-function useAll (app, services) {
17- return reduce((app, [name, service]) => {
18- return app.use(`/${name}`, service)
19- }, app, toPairs(services))
20-}
21-
app/stack/render.jsView
@@ -1,75 +1,0 @@
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- var innerHtml
41- try {
42- innerHtml = renderToString(component)
43- } catch (err) {
44- res.setHeader('content-type', 'text/plain')
45- res.status(500).send(err.stack)
46- }
47-
48- const html = renderFullPage(innerHtml, store.getState())
49-
50- res.send(html)
51- })
52- }
53- })
54- }
55-}
56-
57-function renderFullPage (innerHtml, initialData) {
58- return `
59- <!DOCTYPE html>
60- <html lang="en">
61- <head>
62- <meta charset="utf-8" />
63- <title>Craftworks TodoMVC</title>
64- <meta name="viewport" content="width=device-width, initial-scale=1" />
65- </head>
66- <body>
67- <main>${ innerHtml }</main>
68- <script>
69- window.__data = ${ JSON.stringify(initialData) }
70- </script>
71- <script src="bundle.js"></script>
72- </body>
73- </html>
74- `
75-}
app/stack/static.jsView
@@ -1,8 +1,0 @@
1-const serveStatic = require('serve-static')
2-const { join } = require('path')
3-
4-module.exports = createStatic
5-
6-function createStatic (config) {
7- return serveStatic(config.root, config)
8-}
app/client.jsView
@@ -1,45 +1,0 @@
1-const React = require('react')
2-const { render } = require('react-dom')
3-const { Provider } = require('react-redux')
4-const { Router } = require('react-router')
5-const { createHistory } = require('history')
6-const { syncReduxAndRouter } = require('redux-simple-router')
7-
8-const routes = require('app/routes')
9-const createStore = require('app/store')
10-const fetchElement = require('app/util/fetch-element')
11-
12-if (process.env.NODE_ENV === 'development') {
13-}
14-
15-const store = createStore(window.__data)
16-const history = createHistory()
17-
18-syncReduxAndRouter(history, store)
19-
20-const main = (
21- <Router createElement={fetchElement} history={history}>
22- { routes }
23- </Router>
24-)
25-
26-render(
27- <Provider store={store} key="provider">
28- { main }
29- </Provider>,
30- document.querySelector('main')
31-)
32-
33-if (process.env.NODE_ENV === 'development') {
34- const DevTools = require('app/dev/tools')
35-
36- render(
37- <Provider store={store} key="provider">
38- <div>
39- { main }
40- <DevTools />
41- </div>
42- </Provider>,
43- document.querySelector('main')
44- )
45-}
app/render-browser.jsView
@@ -1,0 +1,45 @@
1+const React = require('react')
2+const { render } = require('react-dom')
3+const { Provider } = require('react-redux')
4+const { Router } = require('react-router')
5+const { createHistory } = require('history')
6+const { syncReduxAndRouter } = require('redux-simple-router')
7+
8+const routes = require('app/routes')
9+const createStore = require('app/store')
10+const fetchElement = require('app/util/fetch-element')
11+
12+if (process.env.NODE_ENV === 'development') {
13+}
14+
15+const store = createStore(window.__data)
16+const history = createHistory()
17+
18+syncReduxAndRouter(history, store)
19+
20+const main = (
21+ <Router createElement={fetchElement} history={history}>
22+ { routes }
23+ </Router>
24+)
25+
26+render(
27+ <Provider store={store} key="provider">
28+ { main }
29+ </Provider>,
30+ document.querySelector('main')
31+)
32+
33+if (process.env.NODE_ENV === 'development') {
34+ const DevTools = require('app/dev/tools')
35+
36+ render(
37+ <Provider store={store} key="provider">
38+ <div>
39+ { main }
40+ <DevTools />
41+ </div>
42+ </Provider>,
43+ document.querySelector('main')
44+ )
45+}
app/server.jsView
@@ -1,11 +1,0 @@
1-const createStack = require('app/stack')
2-
3-module.exports = createServer
4-
5-function createServer (config) {
6- const server = createStack(config)
7-
8- server.listen(config.port)
9-
10- return server
11-}
app/render.jsView
@@ -1,0 +1,87 @@
1+// https://github.com/jlongster/react-redux-universal-hot-example/blob/master/src/server.js
2+
3+const http =require('http')
4+const Url = require('url')
5+const React = require('react')
6+const { renderToString } = require('react-dom/server')
7+const { Provider } = require('react-redux')
8+const { createHistory } = require('history')
9+const { Router, RoutingContext, match } = require('react-router')
10+const sendHtml = require('send-data/html')
11+const sendError = require('send-data/error')
12+const redirect = require('predirect')
13+
14+const createStore = require('app/store')
15+const routes = require('app/routes')
16+const fetchAllData = require('app/util/fetch-all-data')
17+
18+module.exports = createRender
19+
20+function createRender (config) {
21+ const staticUrl = Url.format(config.static.url)
22+
23+ return http.createServer(render)
24+
25+ function render (req, res) {
26+ const store = createStore()
27+
28+ match({
29+ routes: routes,
30+ location: req.url
31+ }, function (err, redirectLocation, renderProps) {
32+ if (redirectLocation) {
33+ redirect(req, res, redirectLocation.pathname + redirectLocation.search)
34+ } else if (err) {
35+ sendError(req, res, { body: err })
36+ } else if (!renderProps) {
37+ sendError(req, res, {
38+ statusCode: 404,
39+ body: new Error('Not found')
40+ })
41+ } else {
42+ fetchAllData(
43+ renderProps.components,
44+ store.getState, store.dispatch,
45+ renderProps.location,
46+ renderProps.params
47+ ).then(function () {
48+ const component = <Provider store={store} key="provider">
49+ <RoutingContext { ...renderProps } />
50+ </Provider>
51+
52+ var innerHtml
53+ try {
54+ innerHtml = renderToString(component)
55+ } catch (err) {
56+ return sendError(req, res, { body: err })
57+ }
58+
59+ const html = renderFullPage(innerHtml, store.getState(), config)
60+
61+ sendHtml(req, res, html)
62+ })
63+ }
64+ })
65+ }
66+
67+ function renderFullPage (innerHtml, initialData) {
68+ return `
69+ <!DOCTYPE html>
70+ <html lang="en">
71+ <head>
72+ <meta charset="utf-8" />
73+ <title>Craftworks TodoMVC</title>
74+ <meta name="viewport" content="width=device-width, initial-scale=1" />
75+ </head>
76+ <body>
77+ <main>${ innerHtml }</main>
78+ <script>
79+ window.__data = ${ JSON.stringify(initialData) }
80+ </script>
81+ <script src="${Url.resolve(staticUrl, 'bundle.js')}"></script>
82+ </body>
83+ </html>
84+ `
85+ }
86+}
87+
app/static.jsView
@@ -1,0 +1,12 @@
1+const http = require('http')
2+
3+module.exports = createStatic
4+
5+function createStatic (config) {
6+ const ecstatic = config.livereload ?
7+ require('ecstatic-lr') : require('ecstatic')
8+
9+ return http.createServer(
10+ ecstatic(config.static)
11+ )
12+}
config/index.jsView
@@ -2,9 +2,27 @@
22 const env = process.env
33 const nodeEnv = env.NODE_ENV
44
55 module.exports = {
6+ render: {
7+ url: {
8+ protocol: 'http:',
9+ hostname: 'localhost',
10+ port: 5000
11+ }
12+ },
613 static: {
14+ url: {
15+ protocol: 'http:',
16+ hostname: 'localhost',
17+ port: 5001
18+ },
719 root: join(__dirname, '..', 'build')
820 },
9- port: env.PORT || 5000
21+ api: {
22+ url: {
23+ protocol: 'http:',
24+ hostname: 'localhost',
25+ port: 5002
26+ }
27+ }
1028 }
package.jsonView
@@ -1,22 +1,26 @@
11 {
22 "name": "business-stack",
33 "version": "0.0.0",
44 "description": "real-world production-quality TodoMVC example",
5- "main": "server",
65 "scripts": {
76 "postinstall": "lnfs app node_modules/app",
87 "lint": "snazzy",
98 "format": "snazzy --format",
109 "test": "npm-run-all -p test:*",
1110 "test:spec": "node app/spec",
1211 "test:feature": "node app/features",
13- "dev:client": "BABEL_ENV=hot watchify client -o build/bundle.js -dv -p browserify-hmr",
12+ "dev:render-browser": "BABEL_ENV=hot watchify app/render -o build/bundle.js -dv -p browserify-hmr",
13+ "dev:render-node": "node-dev render",
1414 "dev:assets": "cpx \"app/assets/**/*\" build -w",
15- "dev:server": "node-dev server",
16- "prod:client": "browserify client -o build/bundle.js -g envify -g uglifyify",
15+ "dev:livereload": "wtch -d build -e html,css,png,gif,jpg | garnish --level debug",
16+ "dev:api": "node-dev api",
17+ "dev:static": "node-dev static",
18+ "prod:render-browser": "browserify app/render -o build/bundle.js -g envify -g uglifyify",
19+ "prod:render-node": "node render",
1720 "prod:assets": "cpx \"app/assets/**/*\" build",
18- "prod:server": "node server",
21+ "prod:api": "node api",
22+ "prod:static": "node static",
1923 "dev": "NODE_ENV=development npm-run-all -p dev:*",
2024 "prod": "NODE_ENV=production npm-run-all -s prod:*"
2125 },
2226 "repository": {
@@ -50,8 +54,10 @@
5054 "ava": "^0.8.0",
5155 "babel-plugin-react-transform": "^2.0.0",
5256 "browserify-hmr": "^0.3.1",
5357 "cuke-tap": "^1.0.2",
58+ "ecstatic-lr": "^1.0.1",
59+ "garnish": "^5.0.1",
5460 "glob": "^6.0.2",
5561 "jsdom": "^7.1.0",
5662 "node-dev": "^2.7.1",
5763 "react-transform-catch-errors": "^1.0.0",
@@ -62,9 +68,10 @@
6268 "redux-devtools-log-monitor": "^1.0.1",
6369 "redux-logger": "^2.0.4",
6470 "run-parallel": "^1.1.4",
6571 "tape": "^4.4.0",
66- "watchify": "^3.6.1"
72+ "watchify": "^3.6.1",
73+ "wtch": "^4.0.1"
6774 },
6875 "dependencies": {
6976 "babel-core": "^6.2.1",
7077 "babel-plugin-transform-object-rest-spread": "^6.1.18",
@@ -78,24 +85,26 @@
7885 "bulkify": "^1.1.1",
7986 "cpx": "^1.2.1",
8087 "css-modules-require-hook": "^2.1.0",
8188 "cssify": "github:ahdinosaur/cssify",
89+ "ecstatic": "^1.4.0",
8290 "envify": "^3.4.0",
8391 "evalify": "^1.0.1",
8492 "feathers": "^1.2.0",
8593 "history": "^1.13.1",
8694 "lnfs-cli": "^1.0.1",
8795 "npm-run-all": "^1.3.2",
8896 "pinkie-promise": "^2.0.0",
97+ "predirect": "^1.1.0",
8998 "ramda": "^0.18.0",
9099 "react": "^0.14.3",
91100 "react-dom": "^0.14.3",
92101 "react-redux": "^4.0.1",
93102 "react-router": "^1.0.0",
94103 "redux": "^3.0.5",
95104 "redux-simple-router": "0.0.10",
96105 "redux-thunk": "^1.0.0",
97- "simple-rc": "github:ahdinosaur/simple-rc",
98- "serve-static": "^1.10.0",
106+ "send-data": "^8.0.0",
107+ "simple-rc": "^1.0.0",
99108 "uglifyify": "^3.0.1"
100109 }
101110 }
api.jsView
@@ -1,0 +1,12 @@
1+require('babel-core/register')
2+
3+const config = require('app/config')
4+const createApi = require('app/api')
5+const Url = require('url')
6+
7+const server = createApi(config)
8+
9+server.listen(config.api.url.port, function () {
10+ const apiUrl = Url.format(config.api.url)
11+ console.log(`api server listening at ${apiUrl}`)
12+})
client.jsView
@@ -1,1 +1,0 @@
1-require('app/client')
server.jsView
@@ -1,7 +1,0 @@
1-require('babel-core/register')
2-require('css-modules-require-hook')
3-
4-const createServer = require('app/server')
5-const config = require('app/config')
6-
7-createServer(config)
render.jsView
@@ -1,0 +1,13 @@
1+require('babel-core/register')
2+require('css-modules-require-hook')
3+
4+const config = require('app/config')
5+const createRender = require('app/render')
6+const Url = require('url')
7+
8+const server = createRender(config)
9+
10+server.listen(config.render.url.port, function () {
11+ const renderUrl = Url.format(config.render.url)
12+ console.log(`render server listening at ${renderUrl}`)
13+})
static.jsView
@@ -1,0 +1,10 @@
1+const config = require('app/config')
2+const createStatic = require('app/static')
3+const Url = require('url')
4+
5+const server = createStatic(config)
6+
7+server.listen(config.static.url.port, function () {
8+ const staticUrl = Url.format(config.static.url)
9+ console.log(`static server listening at ${staticUrl}`)
10+})

Built with git-ssb-web