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} = require('./response.dev');
const responder = new Responder(); let responder = new Responder();
responder.start();
module.exports = () => ({ module.exports = () => ({
@ -12,10 +13,10 @@ module.exports = () => ({
delete headers.host; delete headers.host;
delete headers.connection; delete headers.connection;
return responder.respond(action).then((html) => { return responder.respond(action).then(({html, headers: resHeaders}) => {
return invokeHookSerial('truss/web-response', { return invokeHookSerial('truss/web-response', {
status: 200, status: 200,
headers: defaultHeaders(), headers: {...defaultResponseHeaders(), ...resHeaders},
html, html,
}, headers); }, headers);
}); });
@ -26,10 +27,17 @@ module.exports = () => ({
}, },
}); });
function defaultHeaders() { function defaultResponseHeaders() {
return { return {
Date: (new Date()).toUTCString(), date: (new Date()).toUTCString(),
Connection: 'keep-alive', connection: 'keep-alive',
'Transfer-Encoding': 'chunked',
}; };
} }
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 classnames from 'classnames';
import {Route, Switch} from 'react-router'; import {Route, Switch} from 'react-router';
@ -16,10 +16,10 @@ function App() {
</div>; </div>;
} }
import contempo from 'contempo';
App = contempo(App, require('./index.scss'));
import {hot} from 'react-hot-loader'; import {hot} from 'react-hot-loader';
App = hot(module)(App); App = hot(module)(App);
// import {styler} from '@truss/react'
// App = styler App, require './app.scss'
export default App; export default App;

View File

@ -1,10 +1,8 @@
// import {pkgman} from '@truss/core';
import React from 'react'; import React from 'react';
class Welcome extends React.Component { class Welcome extends React.Component {
render() { render() {
return <div className="welcome"> return <div className="welcome">
<div className="content"> <div className="content">
<h2> <h2>
@ -18,19 +16,13 @@ class Welcome extends React.Component {
} }
thingsToDo() { 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>; const things = <p>You have nothing to do!</p>;
return <div className="things-to-do">{things}</div>; return <div className="things-to-do">{things}</div>;
} }
} }
// import {styler} from '@truss/react' import contempo from 'contempo';
// Welcome = styler Welcome, require './welcome.scss' Welcome = contempo(Welcome, require('./welcome.scss'));
export default Welcome; export default Welcome;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,14 +22,19 @@ exports.Responder = class Responder {
const address = this.address = httpServer.address(); const address = this.address = httpServer.address();
const config = webpackConfig(); const config = webpackConfig();
config.entry.push( for (const i in config.entry) {
`webpack-hot-middleware/client?path=http://${ config.entry[i].unshift(`webpack-hot-middleware/client?path=http://${
frontendHostname}:${address.port frontendHostname}:${address.port
}/__webpack_hmr` }/__webpack_hmr`);
); }
const compiler = webpack(config); const compiler = webpack(config);
this.dm = wdm(compiler, { 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: { stats: {
chunkModules: true, chunkModules: true,
colors: true, colors: true,
@ -58,11 +63,15 @@ exports.Responder = class Responder {
httpServer.on('error', console.error); httpServer.on('error', console.error);
httpServer.listen(backendPort); httpServer.on('close', () => httpServer.removeAllListeners());
}
start() {
this.server.listen(backendPort);
} }
respond({payload: {headers, url}}) { respond({payload: {headers, url}}) {
headers = Object.assign({}, headers); headers = {...headers};
delete headers.host; delete headers.host;
delete headers.connection; delete headers.connection;
@ -85,10 +94,17 @@ exports.Responder = class Responder {
data += chunk; data += chunk;
}); });
res.on('end', () => { res.on('end', () => {
resolve(data); resolve({
html: data,
headers: res.headers
});
}); });
}); });
client.on('error', reject); 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 SOURCE_PATH = process.env.SOURCE_PATH || '/var/node/src';
const OUTPUT_PATH = process.env.OUTPUT_PATH || '/var/node/dist'; const OUTPUT_PATH = process.env.OUTPUT_PATH || '/var/node/dist';
const hashFormat = {
chunk: ('production' === process.env.NODE_ENV) ? '.[chunkhash:20]' : '',
}
module.exports.webpackConfig = function() { module.exports.webpackConfig = function() {
const styleDirectory = path.join(SOURCE_PATH, 'styles');
const cssPrefix = '!style-loader!css-loader!';
const scssPrefix = `${cssPrefix}sass-loader!`;
const config = { const config = {
mode: 'production' !== process.env.NODE_ENV ? 'development' : 'production', mode: 'production' !== process.env.NODE_ENV ? 'development' : 'production',
entry: [ entry: {
index: [
'@babel/polyfill', '@babel/polyfill',
path.join(SOURCE_PATH, 'frontend', 'index.js'), 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: {}, optimization: {},
module: { module: {
rules: [ rules: [
{ {
test: /\.js$/, test: /\.js$/,
exclude: /(node_modules|bower_components)/, exclude: [
/(node_modules\/(?!contempo))/,
],
use: { use: {
loader: 'babel-loader', loader: 'babel-loader',
options: { options: {
@ -39,6 +56,7 @@ module.exports.webpackConfig = function() {
], ],
plugins: [ plugins: [
'@babel/plugin-proposal-object-rest-spread', '@babel/plugin-proposal-object-rest-spread',
'react-hot-loader/babel',
], ],
presets: [ presets: [
'@babel/preset-react', '@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: { output: {
filename: 'index.js', filename: `[name]${hashFormat.chunk}.js`,
chunkFilename: `[id]${hashFormat.chunk}.chunk.js`,
path: path.join(OUTPUT_PATH, 'frontend'), path: path.join(OUTPUT_PATH, 'frontend'),
}, },
plugins: [ plugins: [
@ -61,7 +100,10 @@ module.exports.webpackConfig = function() {
], ],
resolve: { resolve: {
modules: [path.join(OUTPUT_PATH, 'node_modules')], modules: [path.join(OUTPUT_PATH, 'node_modules')],
} },
resolveLoader: {
modules: [path.join(OUTPUT_PATH, 'node_modules')],
},
}; };
if ('production' === config.mode) { if ('production' === config.mode) {
@ -70,6 +112,7 @@ module.exports.webpackConfig = function() {
]; ];
} }
else { else {
config.devtool = 'eval-source-map';
config.plugins.push(new webpack.HotModuleReplacementPlugin()); config.plugins.push(new webpack.HotModuleReplacementPlugin());
} }