Skip to content

Commit

Permalink
merged pulled changes
Browse files Browse the repository at this point in the history
  • Loading branch information
xkawi committed May 6, 2017
2 parents fa4d4f6 + 12fe516 commit 2e5e763
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 103 deletions.
22 changes: 7 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ UPDATE: Checkout [react-universal-saga-modular](https://github.com/xkawi/react-u
## Features

* [Universal](https://medium.com/@mjackson/universal-javascript-4761051b7ae9) rendering, with Client and Server Side Data Fetching
* [React](https://github.com/facebook/react) - latest version `^15.2.0`
* [React](https://github.com/facebook/react) - latest version `^15.4.2`
* [Redux](https://github.com/rackt/redux)'s futuristic [Flux](https://facebook.github.io/react/blog/2014/05/06/flux.html) implementation
* [Redux Saga](https://github.com/yelouafi/redux-saga) to handle all of your Side Effects logic in a central place
* [React Router](https://github.com/rackt/react-router)
* [React Router](https://github.com/ReactTraining/react-router/tree/v2.8.1)
* [Express](http://expressjs.com)
* [Babel](http://babeljs.io) for ES6 and ES7 magic
* [Webpack](http://webpack.github.io) for bundling
Expand All @@ -52,7 +52,7 @@ UPDATE: Checkout [react-universal-saga-modular](https://github.com/xkawi/react-u

Core Concepts to learn if you are new to ReactJS and this repo:

- Dump Components (Component)
- Dumb Components (Component)
- Smart Component (Container)
- Actions - define available action types
- Reducers - given previous state and an action, create a new state
Expand Down Expand Up @@ -176,23 +176,15 @@ Then you set the `className` of your element to match one of the CSS classes in

## Notable Alternatives

* [Next.js](https://github.com/zeit/next.js)
* [create-react-app](https://github.com/facebookincubator/create-react-app)
* [react-universally](https://github.com/ctrlplusb/react-universally)
* [react-boilerplate](https://github.com/mxstbr/react-boilerplate)
* [react-server](https://github.com/redfin/react-server)
* [retax](https://github.com/retaxJS/retax)
* [react-universally](https://github.com/ctrlplusb/react-universally)
* [create-react-app](https://github.com/facebookincubator/create-react-app)

## TODO

- [x] Use Proxy Server for better performance and security
- [ ] Simple authentication saga flow
- [ ] Provide a more realistic example that has navigation and form
- [x] Upgrade to React ^15
- [x] Use [Jest](https://facebook.github.io/jest/) for unit testing
- [ ] Better handling of environment variables
- [x] Borrow some best practices from react-boilerplate (refer to [react-universal-saga-modular](https://github.com/xkawi/react-universal-saga-modular))

Any contribution is welcome.

Cheers,

Kawi
25 changes: 12 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "react-universal-saga",
"description": "Universal React App Starter ft. Redux Saga",
"author": "Kawi Xiao <kawixiao@gmail.com> (http://github.com/xkawi)",
"version": "1.0.3",
"version": "1.1.0",
"repository": {
"type": "git",
"url": "https://github.com/xkawi/react-universal-saga"
Expand Down Expand Up @@ -87,32 +87,31 @@
"dependencies": {
"compression": "^1.6.0",
"express": "^4.13.3",
"express-http-proxy": "^0.10.0",
"file-loader": "^0.9.0",
"express-http-proxy": "^0.11.0",
"file-loader": "^0.11.1",
"hoist-non-react-statics": "^1.2.0",
"humps": "^2.0.0",
"invariant": "^2.2.1",
"isomorphic-fetch": "^2.2.1",
"less": "^2.5.3",
"less-loader": "^2.2.1",
"lodash": "^4.13.1",
"normalizr": "^2.0.1",
"pretty-error": "^2.0.1",
"react": "^15.2.0",
"react-dom": "^15.2.0",
"normalizr": "^3.2.2",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-ga": "^2.1.0",
"react-helmet": "^3.1.0",
"react-redux": "^4.4.5",
"react-helmet": "^5.0.2",
"react-redux": "^5.0.3",
"react-router": "^2.5.2",
"redux": "^3.5.2",
"redux-logger": "^2.6.1",
"redux-saga": "^0.12.0",
"redux-logger": "^3.0.1",
"redux-saga": "^0.14.5",
"scroll-behavior": "^0.8.2",
"serialize-javascript": "^1.1.2",
"serve-favicon": "^2.3.0",
"url-loader": "^0.5.7",
"warning": "^3.0.0",
"webpack-isomorphic-tools": "^2.3.2"
"webpack-isomorphic-tools": "^3.0.2"
},
"devDependencies": {
"autoprefixer": "^6.3.7",
Expand Down Expand Up @@ -168,6 +167,6 @@
"webpack-hot-middleware": "^2.12.0"
},
"engines": {
"node": "6.x.x"
"node": "7.x.x"
}
}
2 changes: 1 addition & 1 deletion src/components/Explore/Explore.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default class Explore extends Component {
<input size="45" ref="input" defaultValue={this.props.value} onKeyUp={this.handleKeyUp} />
<button type="button" className="btn btn-primary" onClick={this.handleGoClick}>Go!</button>
<p>Code on <a href={GITHUB_REPO} target="_blank">Github</a>.</p>
<p>Move the DevTools with Ctrl+W or hide them with Ctrl+H.</p>
<p>Move the DevTools with Ctrl+Q or hide them with Ctrl+H.</p>
</div>
);
}
Expand Down
52 changes: 0 additions & 52 deletions src/components/Login/Login.js

This file was deleted.

1 change: 0 additions & 1 deletion src/components/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export List from './List/List';
export Login from './Login/Login';
export Explore from './Explore/Explore';
export User from './User/User';
export Repo from './Repo/Repo';
2 changes: 1 addition & 1 deletion src/sagas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export function* loadStarred(login, loadMore) {
fetchStarred,
login,
starredByUser.nextPageUrl || firstPageStarredUrl(login)
);
);
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import http from 'http';
import proxy from 'express-http-proxy';
import path from 'path';
import url from 'url';
import PrettyError from 'pretty-error';
import { match, createMemoryHistory } from 'react-router';

import config from './config';
Expand All @@ -17,7 +16,6 @@ import getRoutes from './routes';
import waitAll from './sagas/waitAll';
import { Root } from 'containers';

const pretty = new PrettyError();
const app = new Express();
const server = new http.Server(app);

Expand Down Expand Up @@ -59,7 +57,7 @@ app.use((req, res) => {
if (redirectLocation) {
res.redirect(redirectLocation.pathname + redirectLocation.search);
} else if (error) {
console.error('ROUTER ERROR:', pretty.render(error));
console.error('ROUTER ERROR:', error);
res.status(500);
hydrateOnClient();
} else if (renderProps) {
Expand All @@ -76,7 +74,9 @@ app.use((req, res) => {
.map((component) => component.preload(renderProps.params, req))
.reduce((result, preloader) => result.concat(preloader), []);

store.runSaga(waitAll(preloaders)).done.then(() => {
const runTasks = store.runSaga(waitAll(preloaders));

runTasks.done.then(() => {
global.navigator = { userAgent: req.headers['user-agent'] };

const htmlComponent = <Html assets={assets} component={rootComponent} store={store} />;
Expand All @@ -85,6 +85,8 @@ app.use((req, res) => {
}).catch((e) => {
console.log(e.stack);
});

store.close();
} else {
res.status(404).send('Not found');
}
Expand Down
29 changes: 14 additions & 15 deletions src/services/api/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Schema, arrayOf, normalize } from 'normalizr';
import { schema, normalize } from 'normalizr';
import { camelizeKeys } from 'humps';
import 'isomorphic-fetch';
import config from 'config';
Expand All @@ -22,7 +22,7 @@ const PROXY_ROOT = '/api';

// Fetches an API response and normalizes the result JSON according to schema.
// This makes every API response have the same shape, regardless of how nested it was.
function callApi(endpoint, schema) {
function callApi(endpoint, entitySchema) {
let fullUrl = (endpoint.indexOf(PROXY_ROOT) === -1) ? `${PROXY_ROOT}/${endpoint}` : endpoint;

// If request comes from server side, call API url directly.
Expand All @@ -43,15 +43,16 @@ function callApi(endpoint, schema) {
const camelizedJson = camelizeKeys(json);
const nextPageUrl = getNextPageUrl(response);

return Object.assign({},
normalize(camelizedJson, schema),
return Object.assign(
{},
normalize(camelizedJson, entitySchema),
{ nextPageUrl }
);
);
})
.then(
response => ({ response }),
error => ({ error: error.message || 'Something bad happened.' })
);
);
}

// We use this Normalizr schemas to transform API responses from a nested form
Expand All @@ -60,23 +61,21 @@ function callApi(endpoint, schema) {
// consumption by reducers, because we can easily build a normalized tree
// and keep it updated as we fetch more data.

// Read more about Normalizr: https://github.com/gaearon/normalizr
// Read more about Normalizr: https://github.com/paularmstrong/normalizr

// Schemas for Github API responses.
const userSchema = new Schema('users', {
const userSchema = new schema.Entity('users', {}, {
idAttribute: 'login'
});

const repoSchema = new Schema('repos', {
idAttribute: 'fullName'
});

repoSchema.define({
const repoSchema = new schema.Entity('repos', {
owner: userSchema
}, {
idAttribute: 'fullName'
});

const userSchemaArray = arrayOf(userSchema);
const repoSchemaArray = arrayOf(repoSchema);
const userSchemaArray = new schema.Array(userSchema);
const repoSchemaArray = new schema.Array(repoSchema);

// api services
export const fetchUser = login => callApi(`users/${login}`, userSchema);
Expand Down
2 changes: 1 addition & 1 deletion src/store/configureStore.dev.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createStore, applyMiddleware, compose } from 'redux';
import createLogger from 'redux-logger';
import { createLogger } from 'redux-logger';
import createSagaMiddleware, { END } from 'redux-saga';
import DevTools from 'containers/DevTools/DevTools';
import rootReducer from '../reducers';
Expand Down

0 comments on commit 2e5e763

Please sign in to comment.