Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@
"es2015",
"react"
],
"compact": true,
"env": {
"hmr": {
"presets": [
"react-hmre"
]
}
}
"compact": true
}

3 changes: 3 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[ignore]
.*/node_modules/react/node_modules/.*

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"start": "node build/server/index.js",
"start:dev": "NODE_ENV=development node_modules/nodemon/bin/nodemon.js build/server/index.js",
"start:hot": "HMR=true npm run start:dev",
"hot": "NODE_ENV=development BABEL_ENV=hmr node webpack-dev-server.js"
"hot": "NODE_ENV=development node webpack-dev-server.js",
"flow": "flow"
},
"license": "MIT",
"author": {
Expand All @@ -37,6 +38,7 @@
"webpack"
],
"devDependencies": {
"flow-bin": "^0.22.1",
"nodemon": "^1.8.1",
"webpack-dev-server": "^1.14.1"
},
Expand All @@ -46,12 +48,12 @@
"babel-loader": "^6.2.1",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babel-preset-react-hmre": "^1.0.1",
"css-loader": "^0.23.1",
"deep-freeze": "^0.0.1",
"express": "^4.13.3",
"extract-text-webpack-plugin": "^1.0.1",
"jade": "^1.11.0",
"lodash": "^3.10.1",
"lodash": "^4.6.1",
"null-loader": "^0.1.1",
"postcss-import": "^8.0.2",
"postcss-loader": "^0.8.0",
Expand All @@ -60,6 +62,7 @@
"react-dom": "^0.14.7",
"react-router": "^2.0.0-rc4",
"rimraf": "^2.5.1",
"sculpt": "git@github.com:malectro/sculpt",
"serialize-javascript": "^1.1.2",
"serve-favicon": "^2.3.0",
"source-map-support": "^0.4.0",
Expand Down
59 changes: 45 additions & 14 deletions src/client.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,59 @@
import React from 'react';
import { render } from 'react-dom';
import { Router, browserHistory, match } from 'react-router';
import ReactDOM, {render} from 'react-dom';
import {Router, browserHistory, match} from 'react-router';

import IndexStore from 'src/stores/index';
import routes from 'src/routes';
import { getDependencies } from 'src/utils/index';
import { FluxContext } from 'src/utils/wrappers';
import {getDependencies} from 'src/utils/index';
import FluxRoot from 'src/flux/root.jsx';


const store = new IndexStore();
let store = new IndexStore();
store.initialize(data);

store.initialize(window.data);
let currentRoutes = routes;

// Get route dependencies whenever a route component is rendered.
const routeHandler = (Component, props) => {
getDependencies([props.route], store, props.params);
return <Component {...props} />
return <Component {...props} />;
};

function renderAll() {
match({currentRoutes, location}, () => {
render((
<FluxRoot store={store}>
<Router routes={currentRoutes} history={browserHistory} createElement={routeHandler} />
</FluxRoot>
), document.getElementById('app'));
});
}

match({routes, location }, () => {
render((
<FluxContext store={store}>
<Router routes={routes} history={browserHistory} createElement={routeHandler} />
</FluxContext>
), document.getElementById('app'));
})
renderAll();


if (module.hot) {
module.hot.accept('src/routes', () => {
// NOTE (kyle): i'm not sure if this is sound, but we'll never run HMR on prod
currentRoutes = require('src/routes').default;
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
store.cache.setPerma(true);
renderAll();
store.cache.setPerma(false);
});

module.hot.accept('src/stores/index', () => {
const NewIndexStore = require('src/stores/index').default;
const data = store.serialize();

store = new NewIndexStore();
store.initialize(data);

ReactDOM.unmountComponentAtNode(document.getElementById('app'));
store.cache.setPerma(true);
renderAll();
store.cache.setPerma(false);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the page is in the middle of a getDependencies call to render the new page? does the hot reloading still work?

});
}

window.store = store;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for debugging?

2 changes: 1 addition & 1 deletion src/components/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class App extends React.Component {
return (
<div>
<div className="nav">
Hi world!
Hello world!!
<Link to="/about">About</Link>
<Link to="/">Dashboard</Link>
<Link to="/list">Things</Link>
Expand Down
6 changes: 3 additions & 3 deletions src/components/list/list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import styles from './list.css';
import React from 'react';
import { Link } from 'react-router';

import { subscribeToStore } from 'src/utils/wrappers';
import FluxComponent from 'src/flux/component.jsx';


class List extends React.Component {
render() {
const things = this.context.store.stores.ids.getState() || [];
const things = this.props.store.stores.ids.getOddThings() || [];
return (
<div>
{ things.map(thing => (
Expand All @@ -23,5 +23,5 @@ class List extends React.Component {
}


export default subscribeToStore(List);
export default FluxComponent(List);

8 changes: 4 additions & 4 deletions src/components/thing/thing.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ import styles from './thing.css';

import React from 'react';

import { subscribeToStore } from 'src/utils/wrappers';
import FluxComponent from 'src/flux/component.jsx';


class Thing extends React.Component {
render() {
const id = parseInt(this.props.params.id, 10);
const things = this.context.store.stores.things.getState();
const things = this.props.store.stores.things.getState();
const thing = things && things[id] || {};
return (
<div className={styles.default}>
Thing { thing.id } : { thing.text }
Things { thing.id } : { thing.text }
</div>
);
}
}


export default subscribeToStore(Thing);
export default FluxComponent(Thing);

24 changes: 24 additions & 0 deletions src/flux/component.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* @flow */

import React from 'react';

import typeof Store from 'stores/index';


export default function(Component: Object): Function {
const FluxComponent = (props, context) => {
const { store } = context;
const fluxProps: { store: Store; ref?: Function } = {
store,
};
if (props.fluxRef) {
fluxProps.ref = props.fluxRef;
}
return <Component {...props} {...fluxProps} />;
}
FluxComponent.contextTypes = {
store: React.PropTypes.object,
};
return FluxComponent;
};

45 changes: 45 additions & 0 deletions src/flux/root.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';


/**
* Top-level component that provides flux objects via context to all children.
*
* Should be used as a wrapper around any routing to provide the flux objects
* to the React subtree.
*
* Based on Redux's Provider component:
* https://github.com/rackt/react-redux/blob/master/src/components/Provider.js
*
* NOTE: Only supplies the store in this implementation but could be updated
* to provide other flux-related objects if necessary.
*/
export default class FluxRoot extends React.Component {
constructor(props, context) {
super(props, context);
this.store = props.store;
}

getChildContext() {
return {
store: this.store,
};
}

componentDidMount() {
this.listener = () => this.forceUpdate();
this.store.on('update', this.listener);
}

componentWillUnmount() {
this.store.removeListener('update', this.listener);
}

render() {
return this.props.children;
}
}

FluxRoot.childContextTypes = {
store: React.PropTypes.object,
};

59 changes: 10 additions & 49 deletions src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,63 +4,24 @@ import { Route, IndexRoute } from 'react-router';

import App from 'src/components/app.jsx';
import Dashboard from 'src/components/dashboard/dashboard.jsx';
import About from 'src/components/about/about.jsx';
import Things from 'src/components/things/things.jsx';
import ListOfThings from 'src/components/list/list.jsx';
import Thing from 'src/components/thing/thing.jsx';

import * as actions from 'src/actions/index';

// polyfill webpack require.ensure
if (typeof require.ensure !== 'function') require.ensure = (d, c) => c(require)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this polyfill if we're not doing code splitting


export default (
<Route path='/' component={App} getChildRoutes={(location, cb) => {
require.ensure([], (require) => {
cb(null, [
{
path: 'about',
getComponent(location, cb) {
require.ensure([], () => {
cb(null, require('src/components/about/about.jsx').default);
});
}
},
{
path: 'list',
getComponent(location, cb) {
require.ensure([], () => {
cb(null, require('src/components/things/things.jsx').default);
});
},
dependencies: actions.getIds,
getChildRoutes(location, cb) {
require.ensure([], (require) => {
cb(null, [
{
path: 'thing/:id',
getComponent(location, cb) {
require.ensure([], () => {
cb(null, require('src/components/thing/thing.jsx').default);
});
},
dependencies: actions.getThing,
}
]);
});
},
getIndexRoute(location, cb) {
require.ensure([], (require) => {
cb(null, {
getComponent(location, cb) {
require.ensure([], () => {
cb(null, require('src/components/list/list.jsx').default);
});
}
});
});
}
}
]);
});
}}>
<Route path="/" component={App}>
<IndexRoute component={Dashboard} />
<Route path="about" component={About} />
<Route path='list' component={Things} dependencies={actions.getIds}>
<IndexRoute component={ListOfThings} />
<Route path='thing/:id' component={Thing} dependencies={actions.getThing} />
</Route>
</Route>
);

10 changes: 5 additions & 5 deletions src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import routes from './routes';

import IndexStore from './stores/index';
import { getDependencies } from './utils/index';
import { FluxContext } from './utils/wrappers';
import FluxRoot from './flux/root.jsx';


const DEVELOPMENT = process.env.NODE_ENV === 'development';
Expand Down Expand Up @@ -57,9 +57,9 @@ app.get('/*', function(req, res) {
Promise.all(dependencies)
.then(() => {
const content = renderToString((
<FluxContext store={store}>
<FluxRoot store={store}>
<RouterContext {...renderProps} />
</FluxContext>
</FluxRoot>
));
const data = serialize(store.serialize());
res.render('index', {
Expand All @@ -69,8 +69,8 @@ app.get('/*', function(req, res) {
base: HOT_MODULE_REPLACEMENT ? 'http://localhost:8080' : '',
});
})
.catch((error) => {
console.log(error);
.catch(error => {
console.error(error.stack || error);
res.status(404).send('Not found');
});
} else {
Expand Down
Loading