Skip to content

Commit c67852c

Browse files
committed
first attempt
1 parent bfb71c9 commit c67852c

File tree

17 files changed

+288
-266
lines changed

17 files changed

+288
-266
lines changed

.babelrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"plugins": [
1616
"transform-runtime",
1717
"add-module-exports",
18-
"transform-decorators-legacy"
18+
"transform-decorators-legacy",
19+
"react-loadable/babel"
1920
],
2021
"env": {
2122
"development": {

api/api.js

Lines changed: 15 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,13 @@ import cookieParser from 'cookie-parser';
66
import hooks from 'feathers-hooks';
77
import rest from 'feathers-rest';
88
import socketio from 'feathers-socketio';
9-
import PrettyError from 'pretty-error';
109
import config from './config';
11-
import middleware from './middleware';
1210
import services from './services';
13-
import * as actions from './actions';
14-
import mapUrl from './utils/url.js';
11+
import { actionHandler, logger, notFound, errorHandler } from './middleware';
1512
import auth from './services/authentication';
1613

1714
process.on('unhandledRejection', error => console.error(error));
1815

19-
const pretty = new PrettyError();
2016
const app = feathers();
2117

2218
app
@@ -30,53 +26,25 @@ app
3026
cookie: { maxAge: 60000 }
3127
}))
3228
.use(bodyParser.urlencoded({ extended: true }))
33-
.use(bodyParser.json());
34-
35-
const actionsHandler = async (req, res, next) => {
36-
const splittedUrlPath = req.url
37-
.split('?')[0]
38-
.split('/')
39-
.slice(1);
40-
const { action, params } = mapUrl(actions, splittedUrlPath);
41-
42-
req.app = app;
43-
44-
const catchError = async error => {
45-
console.error('API ERROR:', pretty.render(error));
46-
res.status(error.status || 500).json(error);
47-
};
48-
49-
if (action) {
50-
try {
51-
try {
52-
const result = await action(req, params);
53-
if (result instanceof Function) {
54-
result(res);
55-
} else {
56-
res.json(result);
57-
}
58-
} catch (reason) {
59-
if (reason && reason.redirect) {
60-
return res.redirect(reason.redirect);
61-
}
62-
return catchError(reason);
63-
}
64-
} catch (error) {
65-
return catchError(error);
66-
}
67-
} else {
68-
next();
69-
}
70-
};
71-
72-
app
29+
.use(bodyParser.json())
7330
.configure(hooks())
7431
.configure(rest())
7532
.configure(socketio({ path: '/ws' }))
7633
.configure(auth)
77-
.use(actionsHandler)
34+
.use(actionHandler(app))
7835
.configure(services)
79-
.configure(middleware);
36+
.use(notFound())
37+
.use(logger(app))
38+
.use(errorHandler({
39+
json: (error, req, res) => {
40+
res.json(error);
41+
},
42+
html: (error, req, res) => {
43+
res.json(error);
44+
// render your error view with the error object
45+
// res.render('error', error); // set view engine of express if you want to use res.render
46+
}
47+
}));
8048

8149
if (process.env.APIPORT) {
8250
app.listen(process.env.APIPORT, err => {

api/middleware/actionHandler.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import PrettyError from 'pretty-error';
2+
import * as actions from 'actions';
3+
import mapUrl from 'utils/url';
4+
5+
const pretty = new PrettyError();
6+
7+
export default function actionHandler(app) {
8+
return async (req, res, next) => {
9+
const splittedUrlPath = req.url
10+
.split('?')[0]
11+
.split('/')
12+
.slice(1);
13+
const { action, params } = mapUrl(actions, splittedUrlPath);
14+
15+
req.app = app;
16+
17+
// TODO use next(error) instead of catchError ?
18+
const catchError = async error => {
19+
console.error('API ERROR:', pretty.render(error));
20+
res.status(error.status || 500).json(error);
21+
};
22+
23+
if (action) {
24+
try {
25+
try {
26+
const result = await action(req, params);
27+
if (result instanceof Function) {
28+
result(res);
29+
} else {
30+
res.json(result);
31+
}
32+
} catch (reason) {
33+
if (reason && reason.redirect) {
34+
return res.redirect(reason.redirect);
35+
}
36+
return catchError(reason);
37+
}
38+
} catch (error) {
39+
return catchError(error);
40+
}
41+
} else {
42+
next();
43+
}
44+
};
45+
}

api/middleware/index.js

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,4 @@
1-
import errorHandler from 'feathers-errors/handler';
2-
import notFound from './notFound';
3-
import logger from './logger';
4-
5-
export default function middleware() {
6-
const app = this;
7-
8-
app.use(notFound());
9-
app.use(logger(app));
10-
app.use(errorHandler({
11-
json: (error, req, res) => {
12-
res.json(error);
13-
},
14-
html: (error, req, res) => {
15-
res.json(error);
16-
// render your error view with the error object
17-
// res.render('error', error); // set view engine of express if you want to use res.render
18-
}
19-
}));
20-
}
1+
export actionHandler from './actionHandler';
2+
export errorHandler from 'feathers-errors/handler';
3+
export logger from './logger';
4+
export notFound from './notFound';

api/middleware/notFound.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const errors = require('feathers-errors');
22

3-
export default function notFoundHandler() {
3+
export default function notFound() {
44
return (req, res, next) => {
55
next(new errors.NotFound('Page not found'));
66
};

package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
"axios": "^0.16.2",
123123
"babel-core": "^6.26.0",
124124
"babel-plugin-add-module-exports": "^0.2.1",
125+
"babel-plugin-dynamic-import-node": "^1.1.0",
125126
"babel-plugin-transform-decorators-legacy": "^1.3.4",
126127
"babel-plugin-transform-runtime": "^6.23.0",
127128
"babel-polyfill": "^6.26.0",
@@ -149,6 +150,7 @@
149150
"feathers-nedb": "^2.6.0",
150151
"feathers-rest": "^1.7.3",
151152
"feathers-socketio": "^2.0.0",
153+
"history": "^4.7.2",
152154
"http-proxy": "^1.16.2",
153155
"is-promise": "^2.1.0",
154156
"js-cookie": "^2.1.3",
@@ -164,10 +166,12 @@
164166
"react-bootstrap": "^0.31.2",
165167
"react-dom": "^16.0.0",
166168
"react-helmet": "^5.0.3",
169+
"react-loadable": "^5.2.2",
167170
"react-redux": "^5.0.6",
168-
"react-router": "^3.0.2",
169-
"react-router-bootstrap": "^0.23.1",
170-
"react-router-redux": "^4.0.8",
171+
"react-router": "^4.2.0",
172+
"react-router-bootstrap": "^0.24.4",
173+
"react-router-dom": "^4.2.2",
174+
"react-router-redux": "^5.0.0-alpha.6",
171175
"react-router-scroll": "^0.4.1",
172176
"redux": "^3.6.0",
173177
"redux-auth-wrapper": "^1.0.0",

server.babel.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ var config;
77

88
try {
99
config = JSON.parse(babelrc);
10+
if (Array.isArray(config.plugins)) {
11+
config.plugins.push('dynamic-import-node');
12+
}
1013
} catch (err) {
1114
console.error('==> ERROR: Error parsing your .babelrc.');
1215
console.error(err);

src/client.js

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,26 @@
44
import 'babel-polyfill';
55
import React from 'react';
66
import ReactDOM from 'react-dom';
7-
import { applyRouterMiddleware, Router, browserHistory, match } from 'react-router';
8-
import { bindActionCreators } from 'redux';
9-
import { syncHistoryWithStore, replace } from 'react-router-redux';
10-
import { ReduxAsyncConnect } from 'redux-connect';
7+
import { Provider } from 'react-redux';
8+
import { ConnectedRouter } from 'react-router-redux';
9+
import createBrowserHistory from 'history/createBrowserHistory';
10+
import Loadable from 'react-loadable';
11+
// import { bindActionCreators } from 'redux';
12+
// import { ReduxAsyncConnect } from 'redux-connect';
1113
import { AppContainer as HotEnabler } from 'react-hot-loader';
12-
import { useScroll } from 'react-router-scroll';
14+
// import { useScroll } from 'react-router-scroll';
1315
import { getStoredState } from 'redux-persist';
1416
import localForage from 'localforage';
1517
import { socket, createApp } from 'app';
16-
import { Provider } from 'components';
18+
// import { Provider } from 'components';
1719
import createStore from './redux/create';
1820
import apiClient from './helpers/apiClient';
19-
import getRoutes from './routes';
21+
import routes from './routes';
2022
import isOnline from './utils/isOnline';
2123

2224
const offlinePersistConfig = {
2325
storage: localForage,
24-
whitelist: ['auth', 'info', 'chat']
26+
whitelist: ['auth', 'info', 'chat'],
2527
};
2628

2729
const client = apiClient();
@@ -52,56 +54,55 @@ global.socket = initSocket();
5254
await app.authenticate().catch(() => null);
5355
}
5456

57+
const history = createBrowserHistory();
5558
const data = !online ? { ...storedData, ...window.__data, online } : { ...window.__data, online };
56-
const store = createStore(browserHistory, { client, app, restApp }, data, offlinePersistConfig);
57-
const history = syncHistoryWithStore(browserHistory, store);
58-
59-
const redirect = bindActionCreators(replace, store.dispatch);
60-
61-
const renderRouter = props => (
62-
<ReduxAsyncConnect
63-
{...props}
64-
helpers={{
65-
client,
66-
app,
67-
restApp,
68-
redirect
69-
}}
70-
filter={item => !item.deferred}
71-
render={applyRouterMiddleware(useScroll())}
72-
/>
73-
);
74-
75-
const render = routes => {
76-
match({ history, routes }, (error, redirectLocation, renderProps) => {
77-
ReactDOM.hydrate(
78-
<HotEnabler>
79-
<Provider store={store} app={app} restApp={restApp} key="provider">
80-
<Router {...renderProps} render={renderRouter} history={history}>
81-
{routes}
82-
</Router>
83-
</Provider>
84-
</HotEnabler>,
85-
dest
86-
);
87-
});
59+
const store = createStore(history, { client, app, restApp }, data, offlinePersistConfig);
60+
// const history = syncHistoryWithStore(browserHistory, store);
61+
62+
// const redirect = bindActionCreators(replace, store.dispatch);
63+
//
64+
// const renderRouter = props => (
65+
// <ReduxAsyncConnect
66+
// {...props}
67+
// helpers={{
68+
// client,
69+
// app,
70+
// restApp,
71+
// redirect
72+
// }}
73+
// filter={item => !item.deferred}
74+
// render={applyRouterMiddleware(useScroll())}
75+
// />
76+
// );
77+
78+
const hydrate = _routes => {
79+
ReactDOM.hydrate(
80+
<HotEnabler>
81+
<Provider store={store}>
82+
<ConnectedRouter history={history}>{_routes}</ConnectedRouter>
83+
</Provider>
84+
</HotEnabler>,
85+
dest,
86+
);
8887
};
8988

90-
render(getRoutes(store));
89+
await Loadable.preloadReady().then(hydrated => console.log('HYDRATED', hydrated));
90+
91+
hydrate(routes);
9192

9293
if (module.hot) {
9394
module.hot.accept('./routes', () => {
94-
const nextRoutes = require('./routes')(store);
95-
render(nextRoutes);
95+
const nextRoutes = require('./routes');
96+
hydrate(nextRoutes);
9697
});
9798
}
9899

99100
if (process.env.NODE_ENV !== 'production') {
100101
window.React = React; // enable debugger
101102

102103
if (!dest || !dest.firstChild || !dest.firstChild.attributes || !dest.firstChild.attributes['data-reactroot']) {
103-
console.error('Server-side React render was discarded.' +
104-
'Make sure that your initial render does not contain any client-side code.');
104+
console.error('Server-side React render was discarded.\n' +
105+
'Make sure that your initial render does not contain any client-side code.');
105106
}
106107
}
107108

@@ -110,10 +111,10 @@ global.socket = initSocket();
110111
window.document.body.insertBefore(devToolsDest, null);
111112
const DevTools = require('./containers/DevTools/DevTools');
112113
ReactDOM.hydrate(
113-
<Provider store={store} key="provider">
114+
<Provider store={store}>
114115
<DevTools />
115116
</Provider>,
116-
devToolsDest
117+
devToolsDest,
117118
);
118119
}
119120

src/containers/About/About.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import React, { Component } from 'react';
22
import Helmet from 'react-helmet';
33
import MiniInfoBar from 'components/MiniInfoBar/MiniInfoBar';
4-
import { isLoaded as isInfoLoaded, load as loadInfo } from 'redux/modules/info';
5-
import { asyncConnect } from 'redux-connect';
4+
// import { isLoaded as isInfoLoaded, load as loadInfo } from 'redux/modules/info';
5+
// import { asyncConnect } from 'redux-connect';
66

7-
@asyncConnect([
8-
{
9-
promise: ({ store: { dispatch, getState } }) =>
10-
!isInfoLoaded(getState()) ? dispatch(loadInfo()) : Promise.resolve()
11-
}
12-
])
7+
// @asyncConnect([
8+
// {
9+
// promise: ({ store: { dispatch, getState } }) =>
10+
// !isInfoLoaded(getState()) ? dispatch(loadInfo()) : Promise.resolve()
11+
// }
12+
// ])
1313
export default class About extends Component {
1414
state = {
1515
showKitten: false

0 commit comments

Comments
 (0)