make production build

This commit is contained in:
Eric Hulburd
2016-02-08 18:23:40 -06:00
parent 3cb2320300
commit 109ad432bb
31 changed files with 330 additions and 1387 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
node_modules/
bin/
server/bin/
client/build/

10
client/app.js Normal file
View File

@@ -0,0 +1,10 @@
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import Layout from './dashboard/layout/layout';
ReactDOM.render(
React.createElement(Layout),
document.getElementById('root')
);

View File

@@ -1 +0,0 @@
base.widget.js

View File

@@ -1 +0,0 @@
campaign_orders.widget.js

View File

@@ -1 +0,0 @@
energy_time_series.widget.js

View File

@@ -0,0 +1,25 @@
import layoutRt from './layout.rt.js';
var Layout = React.createClass({
getInitialState: function() {
},
handleResize: function(e) {
this.setState({windowWidth: window.innerWidth});
},
componentDidMount: function() {
window.addEventListener('resize', this.handleResize);
},
setView: function(event) {
var layout = this;
layout.setState({view: event.target.value});
},
render: function() {
return layoutRt.bind(this);
}
});
export default Layout;

View File

@@ -0,0 +1,6 @@
<div>
<select onChange="{this.setView}">
<option value="savings">Savings</option>
<option value="production">Production</option>
</select>
</div>

View File

@@ -0,0 +1,5 @@
import React from 'react/addons';
import _ from 'lodash';
export default function () {
return React.createElement('div', {}, React.createElement('select', { 'onChange': this.setView }, React.createElement('option', { 'value': 'savings' }, 'Savings'), React.createElement('option', { 'value': 'production' }, 'Production')));
};

View File

@@ -0,0 +1,9 @@
#layout {
h1 {
color: red;
}
}
// needless comment
#yada {
div { padding: 200px; }
}

View File

@@ -1,51 +0,0 @@
import React from 'react';
import Relay from 'react-relay';
class PowerTimeSeries extends React.Component {
get timeframes(){
return [
{display: "Today", value: 'today'},
{display: "1 week", value: 'week'},
{display: "1 month", value: 'month'},
{display: "6 months", value: 'half_year'},
{display: "1 year", value: 'year'}
];
}
render() {
var power_time_series = this;
return (
<div>
<h1>Power Time Series</h1>
<ul>
{power_time_series.props.viewer.widgets.edges.map(edge =>
<li key={edge.node.id}>{edge.node.name} (ID: {edge.node.id})</li>
)}
</ul>
<div class="spk-power-time-series-timeframes">
{power_time_series.timeframes.map(timeframe =>
<div data-value="{timeframe.value}" class="spk-power-time-series-timeframe">{timeframe.display}</div>
)}
</div>
</div>
);
}
}
export default Relay.createContainer(PowerTimeSeries, {
fragments: {
viewer: () => Relay.QL`
fragment on User {
widgets(first: 10) {
edges {
node {
id,
name,
},
},
},
}
`,
},
});

View File

@@ -1 +0,0 @@
production_radiation_time_series.widget.js

View File

@@ -1,6 +0,0 @@
## Dashboard Widgets
After initialized:
1. They get/ check the data they need.
2. Render default graph settings.
3. Update graphs based on user input.

View File

@@ -1,15 +0,0 @@
import 'babel-polyfill';
import App from './components/App';
import AppHomeRoute from './routes/AppHomeRoute';
import React from 'react';
import ReactDOM from 'react-dom';
import Relay from 'react-relay';
ReactDOM.render(
<Relay.RootContainer
Component={App}
route={new AppHomeRoute()}
/>,
document.getElementById('root')
);

7
client/style.js Normal file
View File

@@ -0,0 +1,7 @@
// Vendor Stylesheets
require('bootstrap/dist/css/bootstrap.min.css');
require('font-awesome/css/font-awesome.min.css');
// Component Stylesheets
require(__dirname + '/dashboard/layout/layout.scss');

View File

@@ -1,8 +1,12 @@
import gulp from 'gulp';
import yargs from 'yargs';
import webpack from 'webpack';
import gutil from 'gulp-util';
import DB from './server/config/database';
import {PowerDataSeed, HouseSeed} from './server/lib/tasks/seed_data';
import rtCompile from './server/lib/tasks/react_template_compile';
import rt_config from './server/config/react_templates';
gulp.task('generate_power_csv', function(done){
DB.sync().then(()=>{
@@ -21,3 +25,32 @@ gulp.task('save_house_csv', function(done){
HouseSeed.saveCsv(yargs.argv, done);
});
});
gulp.task('compile_react_templates', function() {
gulp.src('./client/react/**/*.rt')
.pipe(rtCompile(rt_config))
.pipe(gulp.dest('./client/react'));
});
gulp.task('build', function(done) {
var config, env;
if (yargs.argv.production){
env = 'production';
} else if (yargs.argv.design){
env = 'design';
} else {
throw new gutil.PluginError("webpack", "Must add '--production' or '--design' option.");
}
config = require(`${__dirname}/server/config/webpack/${env}`);
// run webpack
webpack(config, function(err, stats) {
if(err) throw new gutil.PluginError("webpack", err);
gutil.log("[webpack]", stats.toString({
// output options
}));
done();
});
});

View File

@@ -12,8 +12,6 @@
"jade": "~1.9.2",
"morgan": "~1.5.1",
"serve-favicon": "~2.2.0",
"connect-assets": "~4.7.0",
"connect-jade-static": "~0.2.2",
"node-forge": "~0.6.26",
"sequelize": "~3.15.1",
"pg": "~4.4.3",
@@ -36,20 +34,23 @@
"react-dom": "0.14.3",
"webpack": "1.12.9",
"webpack-dev-server": "1.14.0",
"extract-text-webpack-plugin": "1.0.1",
"jquery": "2.2.0",
"bootstrap": "3.3.6",
"d3": "3.5.12",
"font-awesome": "4.5.0",
"css-loader": "^0.15.5",
"raw-loader": "0.5.1",
"sass-loader": "3.1.2",
"style-loader": "^0.12.3",
"connect-assets":"~4.7.0",
"node-sass": "3.4.2",
"moment-timezone":"0.5.0",
"yargs": "3.32.0",
"extend": "3.0.0"
"extend": "3.0.0",
"through2": "2.0.1"
},
"devDependencies": {
"gulp": "^3.9.0",
"gulp-util": "3.0.7",
"babel-cli": "^6.3.17",
"babel-standalone": "6.4.4",
"react-templates": "0.4.1"

View File

@@ -3,55 +3,26 @@
*/
import express from 'express';
import graphQLHTTP from 'express-graphql';
import path from 'path';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
import schema from './config/graphql/schema';
import DB from './config/database';
import routes from './routes';
const APP_PORT = 3000;
const GRAPHQL_PORT = 8080;
const JS_PORT = 3000;
var rest_api = express();
var app = express();
DB.sync().then(()=>{
rest_api
});
/*
* Compile and Serve Relay App w/ Webpack
*/
var compiler = webpack({
entry: {
app: path.resolve(__dirname, 'lib', 'relay', 'app.relay.js')
},
module: {
loaders: [
{
exclude: /node_modules/,
loader: 'babel',
query: {
plugins: ['./build/babelRelayPlugin'],
},
test: /\.js$/
}
]
},
output: {filename: 'application.js', path: '/'}
});
var dev_server = new WebpackDevServer(compiler, {
contentBase: '/public/',
proxy: {'/graphql': `http://localhost:${GRAPHQL_PORT}`},
publicPath: '/assets/js/',
stats: {colors: true}
});
routes(app);
/*
* Logging, Cookie, JSON Parsing Middleware
*
*/
import favicon from 'serve-favicon';
import logger from 'morgan';
@@ -59,11 +30,10 @@ import cookieParser from 'cookie-parser';
import bodyParser from 'bodyParser';
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());*/
/*
* Serve Vendor Scripts, CSS, and Templates
@@ -71,11 +41,11 @@ app.use(cookieParser());*/
// serve fonts in /assets/fonts
import assets from "connect-assets";
dev_server.app.use("/assets/fonts", express.static("node_modules/bootstrap/dist/fonts"));
dev_server.app.use("/assets/fonts", express.static("node_modules/font-awesome/fonts"));
app.use("/assets/fonts", express.static("node_modules/bootstrap/dist/fonts"));
app.use("/assets/fonts", express.static("node_modules/font-awesome/fonts"));
// serve compiled vendor assets and application.css.
dev_server.app.use(assets({
paths: ["assets/js", "assets/css", "node_modules"],
app.use(assets({
paths: ["./assets/js", "./assets/css", "./../node_modules"],
build: true,
buildDir: false,
//compile: false,
@@ -85,14 +55,13 @@ dev_server.app.use(assets({
dev_server.app.use('/', express.static(path.resolve(__dirname, 'public')));
// view engine set up
dev_server.app.set('views', path.join(__dirname, 'views'));
dev_server.app.set('view engine', 'jade');
dev_server.app.get("/", (req, res, next)=>{
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.get("/", (req, res, next)=>{
res.render("index");
});
console.log("launching dev server")
dev_server.listen(APP_PORT, () => {
app.listen(APP_PORT, () => {
console.log(`App is now running on http://localhost:${APP_PORT}`);
});
@@ -101,13 +70,12 @@ dev_server.listen(APP_PORT, () => {
*/
// catch 404 and forward to error handler
dev_server.use(function(req, res, next) {
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/*
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
@@ -128,7 +96,57 @@ app.use(function(err, req, res, next) {
message: err.message,
error: {}
});
});*/
});
});
/*
* Development Server
*/
import ExtractTextPlugin from "extract-text-webpack-plugin";
var compiler = webpack({
entry: {
app: __dirname + '/../client/app.js',
style: __dirname + '/../client/style.scss'
},
output: {
filename: '[name].js',
path: __dirname + '/../client/build'
},
externals: {
jquery: "$",
d3: "d3"
},
module: {
loaders: [
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")
}, {
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
}
]
},
// Use the plugin to specify the resulting filename (and add needed behavior to the compiler)
plugins: [
new ExtractTextPlugin("style.css", {
allChunks: true
})
]
});
module.exports = dev_server;
var dev_server = new WebpackDevServer(compiler, {
contentBase: __dirname + '/../client/build',
publicPath: "/assets/",
proxy: {
'/data': `http://localhost:${APP_PORT}`
},
stats: {colors: true}
});
module.exports = app;

View File

@@ -1,3 +0,0 @@
/*=require bootstrap/dist/css/bootstrap.min
*= require font-awesome/css/font-awesome.min
*/

View File

@@ -1,3 +0,0 @@
//= require d3/d3.min
//= require jquery/dist/jquery.min
//= require bootstrap/dist/js/bootstrap.min

View File

@@ -24,7 +24,6 @@ class Database {
// add associations
for (var model of Database.models){
console.log(`setting ${model.name}`);
model.set();
}

View File

@@ -1,19 +0,0 @@
import {
fromGlobalId,
nodeDefinitions,
} from 'graphql-relay';
import DB from './../database'
var {nodeInterface, nodeField} = nodeDefinitions(
(globalId) => {
var {graphql_type_name, id} = fromGlobalId(globalId),
model = DB[graphql_type_name];
return model.findOne({where: {id: id}});
},
(instance) => {
return instance.Model().graphql_type;
}
);
export {nodeInterface, nodeField};

View File

@@ -1,27 +0,0 @@
type House implements Node {
id: ID!
name: String!
power_data(after: String, first: Int, before: String, last: Int): [PowerDatum]
habitants(after: String, first: Int, before: String, last: Int): [User]
}
interface Node {
id: ID!
}
type PowerDatum implements Node {
id: ID!
power: Float
time: Int
}
type Query {
node(id: ID!): Node
viewer: User
}
type User implements Node {
id: ID!
username: String!
house: House
}

View File

@@ -1,27 +0,0 @@
import {
GraphQLObjectType,
GraphQLSchema
} from 'graphql';
import {nodeField} from './node';
import DB from './../database';
export default function(){
var queryType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
node: nodeField,
viewer: {
type: DB.User.graphql_type,
resolve: (_, args) => {
return DB.User.findOne({where: {username: 'bethany'}});
}
},
}),
});
return new GraphQLSchema({
query: queryType
});
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
export default {
modules: 'es6',
'target-version': '0.14.3',
'suffix': '.rt'
};

View File

@@ -0,0 +1 @@
design.js

View File

@@ -0,0 +1,41 @@
const ROOT = __dirname + '/../../../';
module.exports = {
entry: {
app: ROOT + 'client/app',
style: ROOT + 'client/style'
},
output: {
filename: '[name].js',
path: ROOT + 'client/build/development'
},
externals: {
jquery: "$",
d3: "d3"
},
module: {
loaders: [
{
test: /\.scss$/,
loader: ['style', 'raw', 'sass']
}, {
test: /\.css$/,
loader: ['style', 'raw']
}
]
},
sassLoader: {
includePaths: [ROOT + 'client', ROOT + 'node_modules']
},
// Use the plugin to specify the resulting filename (and add needed behavior to the compiler)
plugins: [
new ExtractTextPlugin("style.css", {
allChunks: true
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
]
}

View File

@@ -0,0 +1,55 @@
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import webpack from 'webpack';
const ROOT = __dirname + '/../../../';
module.exports = {
entry: {
app: ROOT + 'client/app',
style: ROOT + 'client/style'
},
devtool: 'source-map',
output: {
filename: '[name].min.js',
path: ROOT + 'client/build/production'
},
externals: {
jquery: "$",
d3: "d3"
},
module: {
loaders: [
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract("style-loader", "raw-loader!sass-loader")
}, {
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "raw-loader")
}, {
test: /\.js$/,
loader: 'babel'
}, {
test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "url-loader?limit=10000&minetype=application/font-woff"
}, {
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader"
}
]
},
sassLoader: {
includePaths: [ROOT + 'client', ROOT + 'node_modules']
},
// Use the plugin to specify the resulting filename (and add needed behavior to the compiler)
plugins: [
new ExtractTextPlugin("style.min.css", {
allChunks: true
}),
new webpack.optimize.UglifyJsPlugin({minimize: true}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
]
};

View File

@@ -0,0 +1,58 @@
'use strict';
// through2 is a thin wrapper around node transform streams
import through from 'through2';
import gutil from 'gulp-util';
import rt from 'react-templates';
import path from 'path';
import extend from 'extend';
// Consts
const PLUGIN_NAME = 'gulp-react-templates';
var PluginError = gutil.PluginError;
function normalizeName(name) {
return name.replace(/-/g, '_');
}
export default function (opt) {
function replaceExtension(filePath) {
return filePath + '.js';
}
function transform(file, enc, cb) {
if (file.isNull()) {
return cb(null, file);
}
if (file.isStream()) {
return cb(new PluginError(PLUGIN_NAME, 'Streaming not supported'));
}
var filePath = file.path,
str = file.contents.toString('utf8'),
data;
var options = extend({
filename: file.path,
sourceFiles: [file.relative],
generatedFile: replaceExtension(file.relative),
suffix: '.rt'
}, opt);
if (options.suffix && !options.name) {
options.name = normalizeName(path.basename(filePath, path.extname(filePath))) + options.suffix;
}
try {
data = rt.convertTemplateToReact(str, options);
} catch (err) {
return cb(new PluginError(PLUGIN_NAME, err));
}
file.contents = new Buffer(data);
file.path = replaceExtension(file.path);
cb(null, file);
}
return through.obj(transform);
};

BIN
server/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB