flow: lots

This commit is contained in:
cha0s 2018-09-08 22:56:39 -05:00
parent 2deb7fc289
commit b32f879ccb
20 changed files with 332 additions and 65 deletions

View File

@ -2,7 +2,8 @@ const {invokeHookSerial} = require('@truss/truss');
const {Responder} = require('./response.dev');
const responder = new Responder();
let responder = new Responder();
responder.start();
module.exports = () => ({
@ -12,10 +13,10 @@ module.exports = () => ({
delete headers.host;
delete headers.connection;
return responder.respond(action).then((html) => {
return responder.respond(action).then(({html, headers: resHeaders}) => {
return invokeHookSerial('truss/web-response', {
status: 200,
headers: defaultHeaders(),
headers: {...defaultResponseHeaders(), ...resHeaders},
html,
}, headers);
});
@ -26,10 +27,17 @@ module.exports = () => ({
},
});
function defaultHeaders() {
function defaultResponseHeaders() {
return {
Date: (new Date()).toUTCString(),
Connection: 'keep-alive',
'Transfer-Encoding': 'chunked',
date: (new Date()).toUTCString(),
connection: 'keep-alive',
};
}
if (module.hot) {
module.hot.accept('./response.dev', () => {
responder.stop();
responder = new require('./response.dev').Responder();
responder.start();
});
}

View File

@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import classnames from 'classnames';
import {Route, Switch} from 'react-router';
@ -16,10 +16,10 @@ function App() {
</div>;
}
import contempo from 'contempo';
App = contempo(App, require('./index.scss'));
import {hot} from 'react-hot-loader';
App = hot(module)(App);
// import {styler} from '@truss/react'
// App = styler App, require './app.scss'
export default App;

View File

@ -1,10 +1,8 @@
// import {pkgman} from '@truss/core';
import React from 'react';
class Welcome extends React.Component {
render() {
return <div className="welcome">
<div className="content">
<h2>
@ -18,19 +16,13 @@ class Welcome extends React.Component {
}
thingsToDo() {
// things = for key, value of pkgman.invoke 'perseaThingsToDo'
// <div className={key} key={key}>{value}</div>
// if things.length is 0
const things = <p>You have nothing to do!</p>;
return <div className="things-to-do">{things}</div>;
}
}
// import {styler} from '@truss/react'
// Welcome = styler Welcome, require './welcome.scss'
import contempo from 'contempo';
Welcome = contempo(Welcome, require('./welcome.scss'));
export default Welcome;

View File

@ -2,7 +2,7 @@
<html>
<head>
<meta charset="UTF-8">
<title>Truss</title>
<title>Persea</title>
</head>
<body>
<div class="root"></div>

View File

@ -4,7 +4,8 @@ import {BrowserRouter} from 'react-router-dom';
import DevTools from './dev-tools';
import App from './app';
import App from '../app';
function Root ({store}) {
return <Provider store={store}>
@ -19,7 +20,7 @@ function Root ({store}) {
</Provider>;
};
// import {styler} from '@truss/react'
// Root = styler Root, require './index.scss'
import contempo from 'contempo';
Root = contempo(Root, require('./index.scss'));
export default Root;

View File

@ -1,4 +1,3 @@
if ('production' === process.env.NODE_ENV) {
module.exports = require('./index.prod');
}

View File

@ -2,7 +2,8 @@ import React from 'react';
import {Provider} from 'react-redux';
import {BrowserRouter} from 'react-router-dom';
import App from './app';
import App from '../app';
function Root ({store}) {
return <Provider store={store}>
@ -12,7 +13,7 @@ function Root ({store}) {
</Provider>;
};
// import {styler} from '@truss/react'
// Root = styler Root, require './index.scss'
import contempo from 'contempo';
Root = contempo(Root, require('./index.scss'));
export default Root;

View File

@ -1,20 +1,9 @@
import {combineReducers} from 'redux';
import {reducer as formReducer} from 'redux-form/immutable';
// import {pkgman} from '@truss/core';
// import {createReducer as createResourceReducer} from '../resource'
export default function createRootReducer() {
// dynamicReducers = pkgman.invokeFlat('perseaReducers').reduce(
// ((reducers, map) -> {reducers..., map...}), {}
// )
return combineReducers({
form: formReducer,
// resource: createResourceReducer()
// dynamicReducers...
});
}

View File

@ -1,10 +1,8 @@
import {all, call} from 'redux-saga/effects'
function createRootSaga() {
export default function createRootSaga() {
return function*() {
return yield all([
].map(call));
};
}
export default createRootSaga;

View File

@ -1,4 +1,3 @@
if ('production' === process.env.NODE_ENV) {
module.exports = require('./store.prod');
}

View File

@ -3,16 +3,19 @@ import {compose, createStore, applyMiddleware} from 'redux';
import createRootReducer from './reducer';
import createRootSaga from './saga';
export default function createRootStore() {
// sagaMiddleware = createSagaMiddleware()
const sagaMiddleware = createSagaMiddleware()
// store = createStore createRootReducer(), compose(
// applyMiddleware sagaMiddleware
// )
store = createStore(createRootReducer());
const store = createStore(
createRootReducer(),
compose(
applyMiddleware(sagaMiddleware)
)
);
// sagaMiddleware.run(createRootSaga());
sagaMiddleware.run(createRootSaga());
return store
}

View File

@ -13,6 +13,7 @@
"dependencies": {
"@truss/truss": "1.x",
"classnames": "^2.2.6",
"contempo": "1.x",
"debug": "3.1.0",
"html-webpack-plugin": "3.2.0",
"immutable": "^3.8.2",

View File

@ -22,14 +22,19 @@ exports.Responder = class Responder {
const address = this.address = httpServer.address();
const config = webpackConfig();
config.entry.push(
`webpack-hot-middleware/client?path=http://${
for (const i in config.entry) {
config.entry[i].unshift(`webpack-hot-middleware/client?path=http://${
frontendHostname}:${address.port
}/__webpack_hmr`
);
}/__webpack_hmr`);
}
const compiler = webpack(config);
this.dm = wdm(compiler, {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
},
stats: {
chunkModules: true,
colors: true,
@ -58,11 +63,15 @@ exports.Responder = class Responder {
httpServer.on('error', console.error);
httpServer.listen(backendPort);
httpServer.on('close', () => httpServer.removeAllListeners());
}
start() {
this.server.listen(backendPort);
}
respond({payload: {headers, url}}) {
headers = Object.assign({}, headers);
headers = {...headers};
delete headers.host;
delete headers.connection;
@ -85,10 +94,17 @@ exports.Responder = class Responder {
data += chunk;
});
res.on('end', () => {
resolve(data);
resolve({
html: data,
headers: res.headers
});
});
});
client.on('error', reject);
});
}
stop() {
this.server.close();
}
}

94
styles/forms.scss Normal file
View File

@ -0,0 +1,94 @@
@import './mixins.scss';
button, input, select {
background-color: #333;
color: #CCC;
}
button {
border: 1px solid #333;
padding: 0;
&:hover {
background-color: #555;
}
}
label {
border: none;
border-bottom: 1px solid #333;
margin: 0.25em 0;
display: block;
font-size: 0.8em;
padding: 0.2em;
}
input {
border: 1px solid #333;
text-align: right;
}
.aside {
padding: 0.2em;
}
select {
height: 1.5em;
line-height: 0;
text-align-last: right;
}
button, select, input {
border: 1px solid #333;
}
form {
margin-top: 2em;
@media (min-width: 1024px) {
margin-top: 0;
}
}
.form-row {
@include group;
margin-bottom: 1em;
> .control {
float: left;
}
}
.control {
@include group;
margin-left: 0.75em;
margin-right: 0.75em;
text-align: right;
label {
text-align: left;
}
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
}
.truss-number {
button {
background-color: #333;
&:hover {
background-color: #555;
}
span {
color: #ccc;
}
}
}

55
styles/global.scss Normal file
View File

@ -0,0 +1,55 @@
html, body, .app, .root {
width: 100%;
height: 100%;
}
.aside {
font-size: 0.8em;
}
button {
&:hover {
background-color: #555;
}
}
button, input, select, option {
&[disabled] {
filter: grayscale(1);
opacity: 0.5;
&:hover {
background-color: transparent;
}
}
&:focus {
outline: none;
box-shadow: inset 0 0 1pt 0.5pt #CCC, 0 0 1pt 0.5pt #CCC
}
}
hr {
border: none;
border-bottom: 1px solid #333;
margin: 1em 0;
}
.loading {
align-items: center;
display: flex;
height: 100%;
justify-content: center;
width: 100%;
svg {
height: 25%;
width: 25%;
}
}
.editor.avocado-environment {
height: 100%;
width: 100%;
}

8
styles/mixins.scss Normal file
View File

@ -0,0 +1,8 @@
@mixin group {
&:after {
content: "";
display: table;
clear: both;
}
}

60
styles/reset.css Normal file
View File

@ -0,0 +1,60 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
box-sizing: border-box;
color: #CCCCCC;
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
overflow: hidden;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
ins {
text-decoration: none;
}
select {
font-size: inherit;
}
button {
line-height: 0;
}

View File

@ -17,20 +17,37 @@ module.exports = (config) => {
const SOURCE_PATH = process.env.SOURCE_PATH || '/var/node/src';
const OUTPUT_PATH = process.env.OUTPUT_PATH || '/var/node/dist';
const hashFormat = {
chunk: ('production' === process.env.NODE_ENV) ? '.[chunkhash:20]' : '',
}
module.exports.webpackConfig = function() {
const styleDirectory = path.join(SOURCE_PATH, 'styles');
const cssPrefix = '!style-loader!css-loader!';
const scssPrefix = `${cssPrefix}sass-loader!`;
const config = {
mode: 'production' !== process.env.NODE_ENV ? 'development' : 'production',
entry: [
entry: {
index: [
'@babel/polyfill',
path.join(SOURCE_PATH, 'frontend', 'index.js'),
],
style: [
path.join(cssPrefix, styleDirectory, 'reset.css'),
path.join(scssPrefix, styleDirectory, 'global.scss'),
path.join(scssPrefix, styleDirectory, 'forms.scss'),
],
},
optimization: {},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
exclude: [
/(node_modules\/(?!contempo))/,
],
use: {
loader: 'babel-loader',
options: {
@ -39,6 +56,7 @@ module.exports.webpackConfig = function() {
],
plugins: [
'@babel/plugin-proposal-object-rest-spread',
'react-hot-loader/babel',
],
presets: [
'@babel/preset-react',
@ -47,10 +65,31 @@ module.exports.webpackConfig = function() {
},
},
},
{
test: /\.css$/,
use: [{
loader: 'raw-loader',
}],
},
{
test: /\.scss$/,
use: [{
loader: 'raw-loader',
}, {
loader: 'sass-loader',
options: {
sourceMap: 'production' !== process.env.NODE_ENV,
},
}],
},
],
},
node: {
fs: 'empty',
},
output: {
filename: 'index.js',
filename: `[name]${hashFormat.chunk}.js`,
chunkFilename: `[id]${hashFormat.chunk}.chunk.js`,
path: path.join(OUTPUT_PATH, 'frontend'),
},
plugins: [
@ -61,7 +100,10 @@ module.exports.webpackConfig = function() {
],
resolve: {
modules: [path.join(OUTPUT_PATH, 'node_modules')],
}
},
resolveLoader: {
modules: [path.join(OUTPUT_PATH, 'node_modules')],
},
};
if ('production' === config.mode) {
@ -70,6 +112,7 @@ module.exports.webpackConfig = function() {
];
}
else {
config.devtool = 'eval-source-map';
config.plugins.push(new webpack.HotModuleReplacementPlugin());
}