initial react app(WIP)
parent
05c6dcdf0f
commit
a5e7009a57
|
@ -2,14 +2,17 @@ import BrowserHistory from 'react-router/lib/BrowserHistory';
|
|||
import debugFactory from 'debug';
|
||||
import { Cat } from 'thundercats';
|
||||
|
||||
import AppFactory from '../common/app/appFactory';
|
||||
import app$ from '../common/app/app$.jsx';
|
||||
|
||||
const debug = debugFactory('fcc:client');
|
||||
const DOMContianer = document.getElemenetById('#fCC');
|
||||
const fcc = new Cat();
|
||||
|
||||
// returns an observable
|
||||
fcc.render(AppFactory(BrowserHistory), DOMContianer)
|
||||
app$(BrowserHistory)
|
||||
.flatMap(app => {
|
||||
return fcc.render(app, DOMContianer);
|
||||
})
|
||||
.subscribe(
|
||||
function() {
|
||||
debug('react rendered');
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import Rx from 'rx';
|
||||
import React from 'react';
|
||||
import { Route, Router } from 'react-router';
|
||||
|
||||
// components
|
||||
import App from './App.jsx';
|
||||
import Jobs from './routes/Jobs';
|
||||
import NotFound from './components/NotFound';
|
||||
|
||||
const router$ = Rx.Observable.fromNodeCallback(Router.run, Router);
|
||||
|
||||
export const routes = (
|
||||
<Route handler={ App }>
|
||||
<Route
|
||||
component={ Jobs }
|
||||
path='/jobs' />
|
||||
<Route
|
||||
component={ NotFound }
|
||||
path='*' />
|
||||
</Route>
|
||||
);
|
||||
|
||||
export default function app$(location) {
|
||||
return router$(routes, location);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Router, Route } from 'react-router';
|
||||
|
||||
// components
|
||||
import App from './App.jsx';
|
||||
import Jobs from './screens/App/screens/Jobs';
|
||||
|
||||
module.exports = function appFactory(history) {
|
||||
return (
|
||||
<Router history={ history }>
|
||||
<Route handler={ App }>
|
||||
<Route
|
||||
component={ Jobs }
|
||||
path='/jobs' />
|
||||
</Route>
|
||||
</Router>
|
||||
);
|
||||
};
|
|
@ -1,6 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Nav, Navbar, NavItem } from 'react-bootstrap';
|
||||
import NavItemFCC from './NavItem.jsx';
|
||||
|
||||
export default class extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -34,12 +33,12 @@ export default class extends React.Component {
|
|||
);
|
||||
} else {
|
||||
return (
|
||||
<NavItemFCC
|
||||
aClassName='btn signup-btn signup-btn-nav'
|
||||
<NavItem
|
||||
className='btn signup-btn signup-btn-nav'
|
||||
eventKey={ 2 }
|
||||
href='/login'>
|
||||
Sign In
|
||||
</NavItemFCC>
|
||||
</NavItem>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
var React = require('react/addons');
|
||||
var joinClasses = require('react-bootstrap/lib/utils/joinClasses');
|
||||
var classSet = React.addons.classSet;
|
||||
var BootstrapMixin = require('react-bootstrap').BootstrapMixin;
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
var NavItem = React.createClass({
|
||||
mixins: [BootstrapMixin],
|
||||
export default class extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
propTypes: {
|
||||
static displayName = 'NavItem'
|
||||
static propTypes = {
|
||||
onSelect: React.PropTypes.func,
|
||||
active: React.PropTypes.bool,
|
||||
disabled: React.PropTypes.bool,
|
||||
|
@ -14,31 +15,41 @@ var NavItem = React.createClass({
|
|||
title: React.PropTypes.string,
|
||||
eventKey: React.PropTypes.any,
|
||||
target: React.PropTypes.string
|
||||
},
|
||||
}
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
href: '#'
|
||||
};
|
||||
},
|
||||
handleClick(e) {
|
||||
if (this.props.onSelect) {
|
||||
e.preventDefault();
|
||||
|
||||
render: function () {
|
||||
var {
|
||||
if (!this.props.disabled) {
|
||||
this.props.onSelect(
|
||||
this.props.eventKey,
|
||||
this.props.href,
|
||||
this.props.target
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
disabled,
|
||||
active,
|
||||
href,
|
||||
title,
|
||||
target,
|
||||
children,
|
||||
} = this.props,
|
||||
props = this.props,
|
||||
classes = {
|
||||
} = this.props;
|
||||
|
||||
const classes = {
|
||||
'active': active,
|
||||
'disabled': disabled
|
||||
};
|
||||
|
||||
return (
|
||||
<li {...props} className={joinClasses(props.className, classSet(classes))}>
|
||||
<li
|
||||
className={ joinClasses(props.className, classSet(classes)) }
|
||||
{ ...this.props }>
|
||||
<a
|
||||
href={href}
|
||||
title={title}
|
||||
|
@ -50,17 +61,5 @@ var NavItem = React.createClass({
|
|||
</a>
|
||||
</li>
|
||||
);
|
||||
},
|
||||
|
||||
handleClick: function (e) {
|
||||
if (this.props.onSelect) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!this.props.disabled) {
|
||||
this.props.onSelect(this.props.eventKey, this.props.href, this.props.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = NavItem;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
export default class extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
static displayName = 'NotFound'
|
||||
static propTypes = {}
|
||||
componentDidMount() {
|
||||
}
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ export default {
|
|||
getComponents(cb) {
|
||||
require.ensure([], require => {
|
||||
cb(null, [
|
||||
require('./components/Jobs')
|
||||
require('./components/Jobs.jsx')
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
|
29
gulpfile.js
29
gulpfile.js
|
@ -12,6 +12,11 @@ var gulp = require('gulp'),
|
|||
envify = require('envify/custom'),
|
||||
toVinylWithName = require('vinyl-source-stream'),
|
||||
|
||||
// react app
|
||||
webpack = require('gulp-webpack'),
|
||||
webpackConfig = require('./webpack.config.js'),
|
||||
webpackConfigNode = require('./webpack.config.node.js'),
|
||||
|
||||
// server process
|
||||
nodemon = require('gulp-nodemon'),
|
||||
sync = require('browser-sync'),
|
||||
|
@ -41,6 +46,16 @@ var paths = {
|
|||
clientName: 'lbApp'
|
||||
},
|
||||
|
||||
client: {
|
||||
src: './client',
|
||||
dest: 'public/js'
|
||||
},
|
||||
|
||||
node: {
|
||||
src: './client',
|
||||
dest: 'server/server'
|
||||
},
|
||||
|
||||
syncWatch: [
|
||||
'public/**/*.*'
|
||||
]
|
||||
|
@ -83,6 +98,20 @@ gulp.task('loopback', function() {
|
|||
.pipe(gulp.dest(paths.publicJs));
|
||||
});
|
||||
|
||||
gulp.task('pack-client', function() {
|
||||
return gulp.src(paths.client.src)
|
||||
.pipe(webpack(webpackConfig))
|
||||
.pipe(gulp.dest(paths.client.dest));
|
||||
});
|
||||
|
||||
gulp.task('pack-node', function() {
|
||||
return gulp.src(paths.node.src)
|
||||
.pipe(webpack(webpackConfigNode))
|
||||
.pipe(gulp.dest(paths.node.dest));
|
||||
});
|
||||
|
||||
gulp.task('pack', ['pack-client', 'pack-node']);
|
||||
|
||||
gulp.task('serve', function(cb) {
|
||||
var called = false;
|
||||
nodemon({
|
||||
|
|
12
package.json
12
package.json
|
@ -29,10 +29,13 @@
|
|||
"dependencies": {
|
||||
"accepts": "~1.2.5",
|
||||
"async": "~0.9.0",
|
||||
"babel-core": "^5.6.15",
|
||||
"babel-loader": "^5.2.2",
|
||||
"bcrypt-nodejs": "~0.0.3",
|
||||
"body-parser": "~1.9.3",
|
||||
"chai-jquery": "~2.0.0",
|
||||
"cheerio": "~0.18.0",
|
||||
"classnames": "^2.1.2",
|
||||
"clockwork": "~0.1.1",
|
||||
"compression": "~1.2.1",
|
||||
"connect-mongo": "~0.7.0",
|
||||
|
@ -45,16 +48,20 @@
|
|||
"express": "~4.10.4",
|
||||
"express-flash": "~0.0.2",
|
||||
"express-session": "~1.9.2",
|
||||
"express-state": "^1.2.0",
|
||||
"express-validator": "~2.8.0",
|
||||
"fetchr": "^0.4.16",
|
||||
"font-awesome": "~4.3.0",
|
||||
"forever": "~0.14.1",
|
||||
"frameguard": "^0.2.2",
|
||||
"github-api": "~0.7.0",
|
||||
"gulp-less": "^3.0.3",
|
||||
"gulp-minify-css": "~0.5.1",
|
||||
"gulp-webpack": "^1.5.0",
|
||||
"helmet": "~0.9.0",
|
||||
"helmet-csp": "^0.2.3",
|
||||
"jade": "~1.8.0",
|
||||
"json-loader": "^0.5.2",
|
||||
"less": "~1.7.5",
|
||||
"less-middleware": "~2.0.1",
|
||||
"lodash": "^3.9.3",
|
||||
|
@ -67,6 +74,7 @@
|
|||
"moment": "~2.10.2",
|
||||
"mongodb": "^2.0.33",
|
||||
"morgan": "~1.5.0",
|
||||
"node-libs-browser": "^0.5.2",
|
||||
"node-slack": "0.0.7",
|
||||
"node-uuid": "^1.4.3",
|
||||
"nodemailer": "~1.3.0",
|
||||
|
@ -80,15 +88,17 @@
|
|||
"pmx": "^0.3.16",
|
||||
"ramda": "~0.10.0",
|
||||
"react": "^0.13.3",
|
||||
"react-bootstrap": "^0.23.4",
|
||||
"react-bootstrap": "^0.23.5",
|
||||
"react-router": "^1.0.0-beta1",
|
||||
"request": "~2.53.0",
|
||||
"rx": "^2.5.3",
|
||||
"sanitize-html": "~1.6.1",
|
||||
"source-map-support": "^0.3.2",
|
||||
"thundercats": "^2.0.0-rc6",
|
||||
"twit": "~1.1.20",
|
||||
"uglify-js": "~2.4.15",
|
||||
"validator": "~3.22.1",
|
||||
"webpack": "^1.9.12",
|
||||
"yui": "~3.18.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// appFactory is an es6 module
|
||||
var debug = require('debug')('freecc:servereact');
|
||||
var app$ = require('../common/app/app-stream.jsx').default;
|
||||
var Cat = require('thundercats').Cat;
|
||||
|
||||
var routes = [
|
||||
'/jobs'
|
||||
];
|
||||
|
||||
module.exports = function(app) {
|
||||
var router = app.Router();
|
||||
|
||||
routes.forEach(function(route) {
|
||||
router.get(route, serveReactApp);
|
||||
});
|
||||
|
||||
app.use(router);
|
||||
|
||||
function serveReactApp(req, res, next) {
|
||||
var fcc = new Cat();
|
||||
var decodedUrl = decodeURI(req.path);
|
||||
|
||||
// returns a router wrapped app
|
||||
app$(decodedUrl)
|
||||
// if react-router does not find a route send down the chain
|
||||
.filter(function(data) {
|
||||
var state = data.state;
|
||||
// this may not work with react-router 1.0.0
|
||||
var notFound = state.routes.some(route => route.isNotFound);
|
||||
if (notFound) {
|
||||
debug('tried to find %s but got 404', state.path);
|
||||
next();
|
||||
}
|
||||
return !notFound;
|
||||
})
|
||||
.flatMap(function(app) {
|
||||
// call thundercats renderToString
|
||||
// prefetches data and sets up it up for current state
|
||||
return fcc.renderToString(app);
|
||||
})
|
||||
// makes sure we only get one onNext and closes subscription
|
||||
.firstOrDefault()
|
||||
.flatMap(function(dats) {
|
||||
debug('react rendered');
|
||||
res.expose(dats.data, 'data');
|
||||
// now render jade file with markup injected from react
|
||||
return res.render$('layout-react', { markup: dats.markup });
|
||||
})
|
||||
.subscribe(
|
||||
function(markup) {
|
||||
debug('jade rendered');
|
||||
res.send(markup);
|
||||
},
|
||||
next
|
||||
);
|
||||
}
|
||||
};
|
|
@ -22,6 +22,7 @@ var R = require('ramda'),
|
|||
lessMiddleware = require('less-middleware'),
|
||||
|
||||
passportProviders = require('./passport-providers'),
|
||||
rxMiddleware = require('./utils/rx').rxMiddleware,
|
||||
/**
|
||||
* API keys and Passport configuration.
|
||||
*/
|
||||
|
@ -175,19 +176,22 @@ app.use(helmet.csp({
|
|||
|
||||
passportConfigurator.init();
|
||||
|
||||
// add rx methods to express
|
||||
app.use(rxMiddleware());
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
// Make user object available in templates.
|
||||
res.locals.user = req.user;
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
app.use(
|
||||
loopback.static(path.join(__dirname, '../public'), {
|
||||
maxAge: 86400000
|
||||
})
|
||||
);
|
||||
|
||||
// track when connecting to db starts
|
||||
var startTime = Date.now();
|
||||
boot(app, {
|
||||
appRootDir: __dirname,
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
exports.ids = [1];
|
||||
exports.modules = {
|
||||
|
||||
/***/ 309:
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
|
||||
|
||||
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }
|
||||
|
||||
var _react = __webpack_require__(53);
|
||||
|
||||
var _react2 = _interopRequireDefault(_react);
|
||||
|
||||
var _thundercats = __webpack_require__(22);
|
||||
|
||||
var _reactBootstrap = __webpack_require__(233);
|
||||
|
||||
var _default = (function (_React$Component) {
|
||||
var _class = function _default(props) {
|
||||
_classCallCheck(this, _class2);
|
||||
|
||||
_get(Object.getPrototypeOf(_class2.prototype), 'constructor', this).call(this, props);
|
||||
};
|
||||
|
||||
_inherits(_class, _React$Component);
|
||||
|
||||
var _class2 = _class;
|
||||
|
||||
_createClass(_class2, [{
|
||||
key: 'render',
|
||||
value: function render() {
|
||||
return _react2['default'].createElement(
|
||||
_reactBootstrap.Grid,
|
||||
null,
|
||||
_react2['default'].createElement(
|
||||
_reactBootstrap.Row,
|
||||
null,
|
||||
'foo'
|
||||
)
|
||||
);
|
||||
}
|
||||
}], [{
|
||||
key: 'displayName',
|
||||
value: 'Jobs',
|
||||
enumerable: true
|
||||
}, {
|
||||
key: 'propTypes',
|
||||
value: {
|
||||
jobs: _react.PropTypes.array
|
||||
},
|
||||
enumerable: true
|
||||
}]);
|
||||
|
||||
_class = (0, _thundercats.createContainer)({
|
||||
store: 'JobsStore'
|
||||
})(_class) || _class;
|
||||
return _class;
|
||||
})(_react2['default'].Component);
|
||||
|
||||
exports['default'] = _default;
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ }
|
||||
|
||||
};;
|
||||
//# sourceMappingURL=1.fcc.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["webpack:///./common/app/routes/Jobs/components/Jobs.jsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;kCAAiC,EAAO;;;;wCACR,EAAa;;2CACnB,GAAiB;;;gBAM9B,kBAAC,KAAK,EAAE;;;AACjB,oFAAM,KAAK,EAAE;IACd;;;;;;;;YAQK,kBAAG;AACP,cACE;yBAlBG,IAAI;;SAmBL;2BAnBO,GAAG;;;UAqBJ;QACD,CACP;MACH;;;YAboB,MAAM;;;;YACR;AACjB,WAAI,EAAE,OAfM,SAAS,CAeL,KAAK;MACtB;;;;YAZF,iBAHQ,eAAe,EAGP;AACf,UAAK,EAAE,WAAW;IACnB,CAAC;;IAC2B,mBAAM,SAAS","file":"1.fcc.js","sourcesContent":["import React, { PropTypes } from 'react';\nimport { createContainer } from 'thundercats';\nimport { Grid, Row } from 'react-bootstrap';\n\n@createContainer({\n store: 'JobsStore'\n})\nexport default class extends React.Component {\n constructor(props) {\n super(props);\n }\n\n\n static displayName = 'Jobs'\n static propTypes = {\n jobs: PropTypes.array\n }\n\n render() {\n return (\n <Grid>\n <Row>\n foo\n </Row>\n </Grid>\n );\n }\n}\n\n\n\n/** WEBPACK FOOTER **\n ** ./common/app/routes/Jobs/components/Jobs.jsx\n **/"],"sourceRoot":""}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,9 @@
|
|||
doctype html
|
||||
html(ng-app='profileValidation', lang='en')
|
||||
head
|
||||
include partials/universal-head
|
||||
body.top-and-bottom-margins
|
||||
.container
|
||||
include partials/flash
|
||||
#fcc!= markup
|
||||
script!= state
|
|
@ -0,0 +1,32 @@
|
|||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
devtool: 'sourcemap',
|
||||
entry: './client',
|
||||
output: {
|
||||
filename: 'fcc.js',
|
||||
path: path.join(__dirname, '/public/js'),
|
||||
publicPath: 'public/'
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
include: [
|
||||
path.join(__dirname, 'client/'),
|
||||
path.join(__dirname, 'common/')
|
||||
],
|
||||
loaders: [
|
||||
'babel-loader'
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.json$/,
|
||||
loaders: [
|
||||
'json-loader'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: []
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
|
||||
var nodeModules = fs.readdirSync('node_modules')
|
||||
.filter(function(x) {
|
||||
return ['.bin'].indexOf(x) === -1;
|
||||
})
|
||||
.reduce(function(nodeModules, module) {
|
||||
nodeModules[module] = 'commonjs ' + module;
|
||||
return nodeModules;
|
||||
}, {});
|
||||
|
||||
module.exports = {
|
||||
devtool: 'sourcemap',
|
||||
target: 'node',
|
||||
entry: './server/appEntry',
|
||||
// keeps webpack from bundling modules
|
||||
externals: nodeModules,
|
||||
output: {
|
||||
filename: 'fcc.js',
|
||||
path: path.join(__dirname, '/public/js'),
|
||||
publicPath: 'public/'
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
include: [
|
||||
path.join(__dirname, 'client/'),
|
||||
path.join(__dirname, 'common/')
|
||||
],
|
||||
loaders: [
|
||||
'babel-loader'
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.json$/,
|
||||
loaders: [
|
||||
'json-loader'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.BannerPlugin(
|
||||
'require("source-map-support").install();',
|
||||
{
|
||||
raw: true,
|
||||
entryOnly: false
|
||||
}
|
||||
)
|
||||
]
|
||||
};
|
Loading…
Reference in New Issue