From 24f9750e5f6ec55d962ec7bcd427a7464d8cde9d Mon Sep 17 00:00:00 2001 From: cha0s Date: Mon, 3 Sep 2018 02:03:23 -0500 Subject: [PATCH] chore: initial no style --- actions.js | 35 ++++++++++++++ compose.js | 4 ++ frontend/index.html | 10 ++++ frontend/index.js | 12 +++++ frontend/root/app.js | 25 ++++++++++ frontend/root/app.scss | 6 +++ frontend/root/dev-tools.js | 26 ++++++++++ frontend/root/index.dev.js | 25 ++++++++++ frontend/root/index.js | 7 +++ frontend/root/index.prod.js | 18 +++++++ frontend/root/index.scss | 9 ++++ frontend/root/reducer.js | 20 ++++++++ frontend/root/saga.js | 10 ++++ frontend/root/store.dev.js | 28 +++++++++++ frontend/root/store.js | 7 +++ frontend/root/store.prod.js | 18 +++++++ frontend/root/welcome.js | 36 ++++++++++++++ frontend/root/welcome.scss | 27 +++++++++++ hooks.js | 1 + index.js | 15 ++++++ package.json | 35 ++++++++++++++ response.dev.js | 94 +++++++++++++++++++++++++++++++++++++ response.production.js | 0 webpack.config.js | 77 ++++++++++++++++++++++++++++++ 24 files changed, 545 insertions(+) create mode 100644 actions.js create mode 100644 compose.js create mode 100644 frontend/index.html create mode 100644 frontend/index.js create mode 100644 frontend/root/app.js create mode 100644 frontend/root/app.scss create mode 100644 frontend/root/dev-tools.js create mode 100644 frontend/root/index.dev.js create mode 100644 frontend/root/index.js create mode 100644 frontend/root/index.prod.js create mode 100644 frontend/root/index.scss create mode 100644 frontend/root/reducer.js create mode 100644 frontend/root/saga.js create mode 100644 frontend/root/store.dev.js create mode 100644 frontend/root/store.js create mode 100644 frontend/root/store.prod.js create mode 100644 frontend/root/welcome.js create mode 100644 frontend/root/welcome.scss create mode 100644 hooks.js create mode 100644 index.js create mode 100644 package.json create mode 100644 response.dev.js create mode 100644 response.production.js create mode 100644 webpack.config.js diff --git a/actions.js b/actions.js new file mode 100644 index 0000000..1955bc1 --- /dev/null +++ b/actions.js @@ -0,0 +1,35 @@ +const {invokeHookSerial} = require('@truss/truss'); + +const {Responder} = require('./response.dev'); + +const responder = new Responder(); + +module.exports = () => ({ + + 'truss/http-get': (action) => { + const {payload: {headers}} = action; + + delete headers.host; + delete headers.connection; + + return responder.respond(action).then((html) => { + return invokeHookSerial('truss/web-response', { + status: 200, + headers: defaultHeaders(), + html, + }, headers); + }); + }, + + 'truss/schema': () => { + return {executors: ['truss/http-get']}; + }, +}); + +function defaultHeaders() { + return { + Date: (new Date()).toUTCString(), + Connection: 'keep-alive', + 'Transfer-Encoding': 'chunked', + }; +} diff --git a/compose.js b/compose.js new file mode 100644 index 0000000..7aaf39b --- /dev/null +++ b/compose.js @@ -0,0 +1,4 @@ +module.exports = (config) => { + const backendPort = process.env.PERSEA_BACKPORT || 8004; + config.ports = [`${backendPort}:8004`]; +}; diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..de5139a --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,10 @@ + + + + + Truss + + +
+ + diff --git a/frontend/index.js b/frontend/index.js new file mode 100644 index 0000000..68d567b --- /dev/null +++ b/frontend/index.js @@ -0,0 +1,12 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import Root from './root'; +import createRootStore from './root/store'; + + + +ReactDOM.render( + , + document.querySelector('.root') +); diff --git a/frontend/root/app.js b/frontend/root/app.js new file mode 100644 index 0000000..18de741 --- /dev/null +++ b/frontend/root/app.js @@ -0,0 +1,25 @@ +import * as React from 'react'; + +import classnames from 'classnames'; +import {Route, Switch} from 'react-router'; + +import Welcome from './welcome'; +function App() { + + return
+ + + +
; +} + +import {hot} from 'react-hot-loader'; +App = hot(module)(App); + +// import {styler} from '@truss/react' +// App = styler App, require './app.scss' + +export default App; diff --git a/frontend/root/app.scss b/frontend/root/app.scss new file mode 100644 index 0000000..90a5f4e --- /dev/null +++ b/frontend/root/app.scss @@ -0,0 +1,6 @@ +.app { + background-color: #444444; + color: #fff; + height: 100%; + width: 100%; +} diff --git a/frontend/root/dev-tools.js b/frontend/root/dev-tools.js new file mode 100644 index 0000000..13d404b --- /dev/null +++ b/frontend/root/dev-tools.js @@ -0,0 +1,26 @@ +import React from 'react'; + +import {createDevTools} from 'redux-devtools'; + +import LogMonitor from 'redux-devtools-log-monitor'; +import DockMonitor from 'redux-devtools-dock-monitor'; +import FilterMonitor from 'redux-devtools-filter-actions'; + +const DevTools = createDevTools( + + + + + + + + + +); + +export default DevTools; diff --git a/frontend/root/index.dev.js b/frontend/root/index.dev.js new file mode 100644 index 0000000..35cd4c0 --- /dev/null +++ b/frontend/root/index.dev.js @@ -0,0 +1,25 @@ +import React from 'react'; +import {Provider} from 'react-redux'; +import {BrowserRouter} from 'react-router-dom'; + +import DevTools from './dev-tools'; + +import App from './app'; +function Root ({store}) { + + return + + + + +
+ +
+
+
; +}; + +// import {styler} from '@truss/react' +// Root = styler Root, require './index.scss' + +export default Root; diff --git a/frontend/root/index.js b/frontend/root/index.js new file mode 100644 index 0000000..026a88d --- /dev/null +++ b/frontend/root/index.js @@ -0,0 +1,7 @@ + +if ('production' === process.env.NODE_ENV) { + module.exports = require('./index.prod'); +} +else { + module.exports = require('./index.dev'); +} diff --git a/frontend/root/index.prod.js b/frontend/root/index.prod.js new file mode 100644 index 0000000..13d5720 --- /dev/null +++ b/frontend/root/index.prod.js @@ -0,0 +1,18 @@ +import React from 'react'; +import {Provider} from 'react-redux'; +import {BrowserRouter} from 'react-router-dom'; + +import App from './app'; +function Root ({store}) { + + return + + + + ; +}; + +// import {styler} from '@truss/react' +// Root = styler Root, require './index.scss' + +export default Root; diff --git a/frontend/root/index.scss b/frontend/root/index.scss new file mode 100644 index 0000000..839a45a --- /dev/null +++ b/frontend/root/index.scss @@ -0,0 +1,9 @@ +@media (max-width: 1023px) { + .testing { + margin: 0; + } +} + +.dev-tools { + opacity: 0.9; +} diff --git a/frontend/root/reducer.js b/frontend/root/reducer.js new file mode 100644 index 0000000..64e9be1 --- /dev/null +++ b/frontend/root/reducer.js @@ -0,0 +1,20 @@ +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... + }); +} diff --git a/frontend/root/saga.js b/frontend/root/saga.js new file mode 100644 index 0000000..8d64e9c --- /dev/null +++ b/frontend/root/saga.js @@ -0,0 +1,10 @@ +import {all, call} from 'redux-saga/effects' + +function createRootSaga() { + return function*() { + return yield all([ + ].map(call)); + }; +} + +export default createRootSaga; diff --git a/frontend/root/store.dev.js b/frontend/root/store.dev.js new file mode 100644 index 0000000..ec2be0a --- /dev/null +++ b/frontend/root/store.dev.js @@ -0,0 +1,28 @@ +import createSagaMiddleware from 'redux-saga'; +import {compose, createStore, applyMiddleware} from 'redux'; + +import DevTools from './dev-tools'; + +import createRootReducer from './reducer'; +import createRootSaga from './saga'; + +export default function createRootStore() { + + const sagaMiddleware = createSagaMiddleware(); + + const store = createStore( + createRootReducer(), + compose( + applyMiddleware(sagaMiddleware), + DevTools.instrument() + ) + ); + + module.hot.accept('./reducer', () => { + store.replaceReducer(require('./reducer').default()); + }); + + sagaMiddleware.run(createRootSaga()); + + return store; +} diff --git a/frontend/root/store.js b/frontend/root/store.js new file mode 100644 index 0000000..6323a4f --- /dev/null +++ b/frontend/root/store.js @@ -0,0 +1,7 @@ + +if ('production' === process.env.NODE_ENV) { + module.exports = require('./store.prod'); +} +else { + module.exports = require('./store.dev'); +} diff --git a/frontend/root/store.prod.js b/frontend/root/store.prod.js new file mode 100644 index 0000000..930faa3 --- /dev/null +++ b/frontend/root/store.prod.js @@ -0,0 +1,18 @@ +import createSagaMiddleware from 'redux-saga'; +import {compose, createStore, applyMiddleware} from 'redux'; + +import createRootReducer from './reducer'; +import createRootSaga from './saga'; +export default function createRootStore() { + + // sagaMiddleware = createSagaMiddleware() + + // store = createStore createRootReducer(), compose( + // applyMiddleware sagaMiddleware + // ) + store = createStore(createRootReducer()); + + // sagaMiddleware.run(createRootSaga()); + + return store +} diff --git a/frontend/root/welcome.js b/frontend/root/welcome.js new file mode 100644 index 0000000..7589f1b --- /dev/null +++ b/frontend/root/welcome.js @@ -0,0 +1,36 @@ +// import {pkgman} from '@truss/core'; + +import React from 'react'; +class Welcome extends React.Component { + + render() { + + return
+
+

+ 💕 + Welcome back to Persea + 💕 +

+ {this.thingsToDo()} +
+
; + } + + thingsToDo() { + + // things = for key, value of pkgman.invoke 'perseaThingsToDo' + //
{value}
+ + // if things.length is 0 + const things =

You have nothing to do!

; + + return
{things}
; + } + +} + +// import {styler} from '@truss/react' +// Welcome = styler Welcome, require './welcome.scss' + +export default Welcome; diff --git a/frontend/root/welcome.scss b/frontend/root/welcome.scss new file mode 100644 index 0000000..17925e4 --- /dev/null +++ b/frontend/root/welcome.scss @@ -0,0 +1,27 @@ + +.welcome { + display: flex; + align-items: center; + justify-content: center; + height: 100%; +} + +h2 { + display: block; + font-size: 1.5em; + margin-bottom: 1.5em; + + span { + color: red; + } +} + +.content { + background-color: #333; + padding: 6em; + text-align: center; +} + +.things-to-do div { + margin-bottom: 1em; +} diff --git a/hooks.js b/hooks.js new file mode 100644 index 0000000..17f95fe --- /dev/null +++ b/hooks.js @@ -0,0 +1 @@ +module.exports = () => ({}); diff --git a/index.js b/index.js new file mode 100644 index 0000000..85f1318 --- /dev/null +++ b/index.js @@ -0,0 +1,15 @@ +import {createDispatcher} from '@truss/truss'; + +const dispatcher = createDispatcher(); +dispatcher.lookupActions(require('./actions')); +dispatcher.lookupHooks(require('./hooks')); +dispatcher.connect(); + +if (module.hot) { + module.hot.accept('./actions', () => { + dispatcher.lookupActions(require('./actions')); + }); + module.hot.accept('./hooks', () => { + dispatcher.lookupHooks(require('./hooks')); + }); +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ff20792 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "persea", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "node -e '' -r '@truss/truss/task/build'", + "default": "yarn run dev", + "dev": "node -e '' -r '@truss/truss/task/scaffold'" + }, + "author": "cha0s", + "license": "MIT", + "dependencies": { + "@truss/truss": "1.x", + "classnames": "^2.2.6", + "debug": "3.1.0", + "html-webpack-plugin": "3.2.0", + "immutable": "^3.8.2", + "react": "^16.4.2", + "react-dom": "^16.4.2", + "react-hot-loader": "^4.3.5", + "react-redux": "^5.0.7", + "react-router": "^4.3.1", + "react-router-dom": "^4.3.1", + "redux": "^4.0.0", + "redux-devtools": "^3.4.1", + "redux-devtools-dock-monitor": "^1.1.3", + "redux-devtools-filter-actions": "^1.2.2", + "redux-devtools-log-monitor": "^1.4.0", + "redux-form": "^7.4.2", + "redux-saga": "^0.16.0", + "webpack-dev-middleware": "3.1.3", + "webpack-hot-middleware": "2.22.3" + } +} diff --git a/response.dev.js b/response.dev.js new file mode 100644 index 0000000..a85f2b9 --- /dev/null +++ b/response.dev.js @@ -0,0 +1,94 @@ + +const http = require('http'); + +const webpack = require('webpack'); +const wdm = require('webpack-dev-middleware'); +const whm = require('webpack-hot-middleware'); + +const debug = require('debug')('truss:persea'); + +const {webpackConfig} = require('./webpack.config'); + +const backendHostname = process.env.PERSEA_BACKHOST || 'persea'; +const backendPort = process.env.PERSEA_BACKPORT || 8004; +const frontendHostname = process.env.PERSEA_FRONTHOST || 'localhost'; + +exports.Responder = class Responder { + + constructor() { + const httpServer = this.server = http.createServer(); + + httpServer.on('listening', () => { + const address = this.address = httpServer.address(); + const config = webpackConfig(); + + config.entry.push( + `webpack-hot-middleware/client?path=http://${ + frontendHostname}:${address.port + }/__webpack_hmr` + ); + + const compiler = webpack(config); + this.dm = wdm(compiler, { + stats: { + chunkModules: true, + colors: true, + context: process.cwd(), + }, + }); + this.hm = whm(compiler, { + path: '/__webpack_hmr', + }); + + debug(`HTTP listening on ${JSON.stringify(address)}...`); + }); + + httpServer.on('request', (req, res) => { + this.dm(req, res, (error) => { + if (error) { + return console.error(error); + } + this.hm(req, res, (error) => { + if (error) { + return console.error(error); + } + }); + }); + }); + + httpServer.on('error', console.error); + + httpServer.listen(backendPort); + } + + respond({payload: {headers, url}}) { + headers = Object.assign({}, headers); + + delete headers.host; + delete headers.connection; + + // forward to internal HTTP + return new Promise((resolve, reject) => { + + const options = { + headers, + backendHostname, + path: url, + port: this.address.port, + }; + + const client = http.get(options); + client.on('response', (res) => { + let data = ''; + res.setEncoding('utf8'); + res.on('data', (chunk) => { + data += chunk; + }); + res.on('end', () => { + resolve(data); + }); + }); + client.on('error', reject); + }); + } +} diff --git a/response.production.js b/response.production.js new file mode 100644 index 0000000..e69de29 diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..404dc3e --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,77 @@ +const path = require('path'); + +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); +const webpack = require('webpack'); + +module.exports = (config) => { + + if ('production' === config.mode) { + return [config, module.exports.webpackConfig()]; + } + else { + return config; + } +}; + +const SOURCE_PATH = process.env.SOURCE_PATH || '/var/node/src'; +const OUTPUT_PATH = process.env.OUTPUT_PATH || '/var/node/dist'; + +module.exports.webpackConfig = function() { + + const config = { + mode: 'production' !== process.env.NODE_ENV ? 'development' : 'production', + entry: [ + '@babel/polyfill', + path.join(SOURCE_PATH, 'frontend', 'index.js'), + ], + optimization: {}, + module: { + rules: [ + { + test: /\.js$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader', + options: { + babelrcRoots: [ + OUTPUT_PATH, + ], + plugins: [ + '@babel/plugin-proposal-object-rest-spread', + ], + presets: [ + '@babel/preset-react', + '@babel/preset-env', + ], + }, + }, + }, + ], + }, + output: { + filename: 'index.js', + path: path.join(OUTPUT_PATH, 'frontend'), + }, + plugins: [ + new HtmlWebpackPlugin({ + title: 'Truss', + template: path.join(SOURCE_PATH, 'frontend', 'index.html'), + }), + ], + resolve: { + modules: [path.join(OUTPUT_PATH, 'node_modules')], + } + }; + + if ('production' === config.mode) { + config.optimization.minimizer = [ + new UglifyJsPlugin({cache: false}) + ]; + } + else { + config.plugins.push(new webpack.HotModuleReplacementPlugin()); + } + + return config; +}