Skip to content
This repository has been archived by the owner on Jan 2, 2018. It is now read-only.

Commit

Permalink
Merge pull request #11 from rocjs/feature/general-improvements
Browse files Browse the repository at this point in the history
General improvements
  • Loading branch information
dlmr committed May 3, 2016
2 parents a5c5483 + 97cdf5a commit 859b9af
Show file tree
Hide file tree
Showing 24 changed files with 294 additions and 324 deletions.
4 changes: 2 additions & 2 deletions examples/complex/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"author": "VG",
"license": "MIT",
"dependencies": {
"redux-fetcher": "~1.0.1",
"redux-api-middleware": "vgno/redux-api-middleware#v1.0.0-beta5",
"redux-fetcher": "~2.0.0",
"redux-api-middleware": "~1.0.2",
"roc-package-web-app-react": "*"
},
"devDependencies": {
Expand Down
8 changes: 6 additions & 2 deletions examples/complex/roc.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ module.exports = {
settings: {
runtime: {
applicationName: 'My Roc Application',
serve: ['files', 'build/client']
serve: ['files', 'build/client'],
fetch: {
server: ['fetch', 'defer']
}
},
build: {
koaMiddlewares: 'src/koa-middlewares.js',
reduxMiddlewares: 'src/middlewares.js',
reducers: 'src/reducers.js',
routes: 'src/routes.js'
routes: 'src/routes.js',
templateValues: 'src/template-values.js'
}
}
};
28 changes: 21 additions & 7 deletions examples/complex/src/components/about/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
import React, { Component } from 'react';
import { provideHooks } from 'redial';

@provideHooks({ fetch: () => new Promise((resolve) => {
setTimeout(() => {
console.log('Completed!');
resolve();
}, 2000);
})})
@provideHooks({
fetch: (locals) => new Promise((resolve) => {
if (locals.force || !locals.getProps()) {
setTimeout(() => {
locals.setProps({color: 'blue'});
resolve();
}, 2500);
} else {
resolve();
}
}),
defer: (locals) => {
locals.setProps({color: 'red'});
},
})
export default class About extends Component {
render() {
// "Remove" props that are different on the server and the client - only structure from JSON.stringify
const { location, routes, route, ...props } = this.props;

return (
<div>
<h1>About us</h1>
<h1 style={{color: this.props.color}}>About us</h1>
<button onClick={ () => this.props.reload() }>Reload</button>
<pre>{ JSON.stringify(props, null, 2) }</pre>
</div>
);
}
Expand Down
10 changes: 8 additions & 2 deletions examples/complex/src/components/app/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import React, { Component } from 'react';
import { IndexLink, Link } from 'react-router';
import Link from 'react-router/lib/Link';
import IndexLink from 'react-router/lib/IndexLink';

export default class App extends Component {
static propTypes = {
children: React.PropTypes.object
};

render() {
const style = {
opacity: this.props.loading ? 0.5 : 1,
transition: this.props.loading ? 'opacity 250ms ease 300ms' : ''
}
return (
<div>
<div style={style}>
<nav>
<ul>
<li><IndexLink to="/">Home</IndexLink></li>
<li><Link to="/about/">About</Link></li>
<li><Link to="/simple/">Simple</Link></li>
</ul>
</nav>
{ this.props.children }
Expand Down
11 changes: 11 additions & 0 deletions examples/complex/src/components/simple/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, { Component } from 'react';

export default class Simple extends Component {
render() {
return (
<div>
<h1>Nothing</h1>
</div>
);
}
}
11 changes: 7 additions & 4 deletions examples/complex/src/routes.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import Route from 'react-router/lib/Route';
import IndexRoute from 'react-router/lib/IndexRoute';

import App from './components/app';
import Main from './components/main';
import About from './components/about';
import Simple from './components/simple';

export default () => (
<Route component={ App }>
<IndexRoute component={ Main } />
<Route path="about/" component={ About } />
<Route component={ App } value={false}>
<IndexRoute component={ Main } value={true}/>
<Route path="about/" component={ About } data={2} />
<Route path="simple/" component={ Simple } data={3} />
</Route>
);
5 changes: 5 additions & 0 deletions examples/complex/src/template-values.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default function getTemplateValues(/* { koaState, settings, reduxState } */) {
return {
bodyClass: 'main'
};
}
14 changes: 13 additions & 1 deletion packages/roc-package-web-app-react-dev/src/builder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ export default () => ({ settings: { build: buildSettings }, previousValue: rocBu
);
}

const hasTemplateValues = !!(buildSettings.templateValues && fileExists(buildSettings.templateValues));
if (hasTemplateValues) {
const templateValues = getAbsolutePath(buildSettings.templateValues);

buildConfig.plugins.push(
new builder.DefinePlugin({
TEMPLATE_VALUES: JSON.stringify(templateValues)
})
);
}

buildConfig.plugins.push(
new builder.DefinePlugin({
USE_DEFAULT_REDUX_REDUCERS: buildSettings.useDefaultReducers,
Expand All @@ -100,7 +111,8 @@ export default () => ({ settings: { build: buildSettings }, previousValue: rocBu

HAS_REDUX_REDUCERS: hasReducers,
HAS_REDUX_MIDDLEWARES: hasMiddlewares,
HAS_CLIENT_LOADING: hasClientLoading
HAS_CLIENT_LOADING: hasClientLoading,
HAS_TEMPLATE_VALUES: hasTemplateValues
})
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ export default {

clientLoading: '',
// Consider using the config function to merge this with the previous
resources: ['roc-package-web-app-react/styles/base.css']
resources: ['roc-package-web-app-react/styles/base.css'],

templateValues: 'template-values.js'
},
dev: {
// A11Y not play nice with Redux Devtools
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default {
' documentation for what middlewares that are included.',

clientLoading: 'The React component to use on the first client load while fetching data, will only ' +
'be used if clientBlocking is set to true.'
'be used if some blocking hooks are defined.'
},
dev: {
a11y: 'If A11Y validation should be active. Currently it´s suggested to not enable reduxDevtools ' +
Expand Down
157 changes: 89 additions & 68 deletions packages/roc-package-web-app-react/app/client/create-client.js
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global __DEV__ HAS_CLIENT_LOADING ROC_CLIENT_LOADING ROC_PATH */
/* global __DEV__ HAS_CLIENT_LOADING ROC_CLIENT_LOADING ROC_PATH HAS_REDUX_REDUCERS */

import React from 'react';
import ReactDOM from 'react-dom';
Expand All @@ -7,15 +7,14 @@ import Router from 'react-router/lib/Router';
import useRouterHistory from 'react-router/lib/useRouterHistory';
import { createHistory } from 'history';

import { Provider } from 'react-redux';
import { syncHistoryWithStore } from 'react-router-redux';
import debug from 'debug';

import { RedialContext } from 'react-router-redial';
import { rocConfig } from '../shared/universal-config';

const clientDebug = debug('roc:client');

const basename = ROC_PATH === '/' ? null : ROC_PATH;
const basename = ROC_PATH === '/' ? '' : ROC_PATH;

/**
* Client entry point for React applications.
Expand Down Expand Up @@ -66,87 +65,109 @@ export default function createClient({ createRoutes, createStore, mountNode }) {
const render = () => {
const node = document.getElementById(mountNode);

let component;
const history = useRouterHistory(createHistory)({
basename: basename
let history = useRouterHistory(createHistory)({
basename
});

if (createStore) {
const store = createStore(history, window.FLUX_STATE);
const theHistory = syncHistoryWithStore(history, store);
let initialLoading = null;
if (HAS_CLIENT_LOADING) {
initialLoading = require(ROC_CLIENT_LOADING).default;
}

const ReduxContext = require('./redux-context').default;
let routes;
let locals = {};
let createComponent = [(component) => component];
let createDevComponent = [(component) => component];

let initalClientLoading = null;
if (HAS_CLIENT_LOADING) {
initalClientLoading = require(ROC_CLIENT_LOADING).default;
}
if (HAS_REDUX_REDUCERS && createStore) {
const { Provider } = require('react-redux');
const { syncHistoryWithStore } = require('react-router-redux');

const store = createStore(history, window.FLUX_STATE);
history = syncHistoryWithStore(history, store);

routes = createRoutes(store);
locals = {
dispatch: store.dispatch,
getState: store.getState
};

component = (
<Router
history={ theHistory }
routes={ createRoutes(store) }
render={ (props) => <ReduxContext {...props} /> }
store={ store }
blocking={ rocConfig.runtime.clientBlocking }
initalClientLoading={ initalClientLoading }
/>
);
createComponent.push((component) => (
<Provider store={ store }>
{ component }
</Provider>
));

if (__DEV__) {
if (rocConfig.dev.reduxDevtools.enabled) {
if (rocConfig.dev.reduxDevtools.enabled && !window.devToolsExtension) {
const DevTools = require('./dev-tools').default;

if (rocConfig.runtime.ssr) {
clientDebug('You will see a "Warning: React attempted to reuse markup in a container but the ' +
'checksum was invalid." message. That\'s because the redux-devtools are enabled.');
}

component = (
<div>
{ component }
<DevTools />
</div>
);
createDevComponent.push((component) => (
<Provider store={ store }>
<span>
{ component }
<DevTools />
</span>
</Provider>
));
} else if (rocConfig.dev.reduxDevtools.enabled) {
console.log('Found Redux Devtools Chrome extension, will use that over default one.');
}
}
} else {
routes = createRoutes();
}

if (rocConfig.dev.yellowbox.enabled) {
const YellowBox = require('yellowbox-react').default;

/* eslint-disable no-console */
console.ignoredYellowBox = rocConfig.dev.yellowbox.ignore;
/* eslint-enable */

if (rocConfig.runtime.ssr) {
clientDebug('You will see a "Warning: React attempted to reuse markup in a container but the ' +
'checksum was invalid." message. That\'s because the YellowBox is enabled.');
}
if (__DEV__ && rocConfig.dev.yellowbox.enabled) {
const YellowBox = require('yellowbox-react').default;

component = (
<div>
{ component }
<YellowBox />
</div>
);
}
}
/* eslint-disable no-console */
console.ignoredYellowBox = rocConfig.dev.yellowbox.ignore;
/* eslint-enable */

component = (
<Provider store={ store }>
createDevComponent.push((component) => (
<span>
{ component }
</Provider>
);
} else {
component = (
<Router
history={ history }
routes={ createRoutes() }
/>
);
<YellowBox />
</span>
));
}

ReactDOM.render(component, node);
const finalComponent = compose(createComponent)(
<Router
history={ history }
routes={ routes }
render={ (props) => (
<RedialContext
{ ...props }
locals={ locals }
blocking={ rocConfig.runtime.fetch.client.blocking }
defer={ rocConfig.runtime.fetch.client.defer }
parallel={ rocConfig.runtime.fetch.client.parallel }
initialLoading={ initialLoading }
/>
)}
/>
);

ReactDOM.render(finalComponent, node);

if (__DEV__) {
const devNode = document.createElement('div');
node.parentNode.insertBefore(devNode, node.nextSibling);
ReactDOM.render(compose(createDevComponent)(null), devNode);
}
};

render();
}

function compose(funcs) {
if (funcs.length === 0) {
return (arg) => arg;
}

const last = funcs[funcs.length - 1];
const rest = funcs.slice(0, -1);
return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args));
}
Loading

0 comments on commit 859b9af

Please sign in to comment.