├── .gitignore ├── LICENSE ├── README.md ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | tmp/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Yoshua Wuyts 2 | 3 | Permission is hereby granted, free of charge, to any person ob- 4 | taining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without restric- 6 | tion, including without limitation the rights to use, copy, modi- 7 | fy, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is fur- 9 | nished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONIN- 17 | FRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # playground-virtual-app 2 | Playing around with some `virtual-*` tech. Creates a minimal (`11Kb`) modern JS 3 | application that can be rendered on both client and server. 4 | 5 | ## Installation 6 | ```sh 7 | $ git clone git@github.com:yoshuawuyts/playground-virtual-app.git 8 | ``` 9 | 10 | ## Features 11 | - [x] [router](https://github.com/yoshuawuyts/sheet-router) 12 | - [x] [virtual-dom rendering](https://github.com/Matt-Esch/virtual-dom) 13 | - [x] [immutable data structures](https://github.com/Raynos/xtend) 14 | - [x] [unidirectional event flow](https://github.com/sethvincent/store-emitter) 15 | - [x] [human readable templates](https://github.com/substack/hyperx) 16 | - [x] [inline stylesheet declaration](https://github.com/sheetify/sheetify) 17 | 18 | ## Usage 19 | ```txt 20 | Lifecycle scripts included in playground-virtual-app: 21 | start 22 | NODE_ENV=development budo . --pushstate 23 | 24 | available via `npm run-script`: 25 | build 26 | NODE_ENV=production browserify . | uglifyjs 27 | disc 28 | NODE_ENV=production browserify . --full-paths | uglifyjs | discify --open 29 | size 30 | npm run build | gzip-size | pretty-bytes 31 | ``` 32 | 33 | ## License 34 | [MIT](https://tldrlegal.com/license/mit-license) 35 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const history = require('sheet-router/history') 2 | const bridge = require('sheet-router/bridge') 3 | const sheetRouter = require('sheet-router') 4 | const createApp = require('virtual-app') 5 | const vdom = require('virtual-dom') 6 | const hyperx = require('hyperx') 7 | const xtend = require('xtend') 8 | const sf = require('sheetify') 9 | 10 | const hx = hyperx(vdom.h) 11 | 12 | // initialize and attach 13 | const app = createApp(document.body, vdom) 14 | const initialState = { count: 0, mod: 1, location: document.location.href } 15 | const render = app.start(modifyState, initialState) 16 | const router = createRouter() 17 | history(function (href) { 18 | app.store({ type: 'location', location: href }) 19 | }) 20 | bridge(render, function (state) { 21 | return router(state.location, app.h) 22 | }) 23 | 24 | // routing 25 | function createRouter () { 26 | return sheetRouter('/404', function (r, t) { 27 | return [ 28 | t('/', template(singleHead, okMain)), 29 | t('/double', template(multiHead, okMain)), 30 | t('/404', template(errorHead, errMain)) 31 | ] 32 | }) 33 | } 34 | 35 | // manage state changes 36 | function modifyState (action, state) { 37 | if (action.type === 'location') { 38 | if (/double/.test(action.location)) { 39 | return xtend(state, { location: action.location, mod: 2 }) 40 | } else { 41 | return xtend(state, { location: action.location, mod: 1 }) 42 | } 43 | } 44 | if (action.type === 'increment') { 45 | return xtend(state, { count: state.count + state.mod }) 46 | } 47 | if (action.type === 'decrement') { 48 | return xtend(state, { count: state.count - state.mod }) 49 | } 50 | } 51 | 52 | // render views 53 | function template (head, main) { 54 | return function template (params, h, state) { 55 | const prefix = sf` 56 | nav > a { 57 | font-size: 20px; 58 | } 59 | ` 60 | 61 | return hx` 62 |
63 | 68 | ${head(params, h, state)} 69 | ${main(params, h, state)} 70 |
71 | ` 72 | } 73 | } 74 | 75 | // main body if all is good 76 | function okMain (params, h, state) { 77 | return hx` 78 |
79 |

modifier is ${state.mod}

80 |
count: ${state.count}
81 | 84 | 87 | 88 | ` 89 | } 90 | 91 | // main body if all is bad 92 | function errMain (params, h, state) { 93 | const prefix = sf` 94 | span { color: red } 95 | ` 96 | 97 | return hx` 98 |
99 | NOPE YOU BROKE IT 100 |
101 | ` 102 | } 103 | 104 | // head component 105 | function singleHead (params, h, state) { 106 | return hx` 107 |

super single

108 | ` 109 | } 110 | 111 | // another head component 112 | function multiHead (params, h, state) { 113 | return hx` 114 |

double up!

115 | ` 116 | } 117 | 118 | // signal an error 119 | function errorHead (params, h, state) { 120 | return hx` 121 |

OH NO!

122 | ` 123 | } 124 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playground-virtual-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "NODE_ENV=development budo . --pushstate", 8 | "build": "NODE_ENV=production browserify . | uglifyjs", 9 | "disc": "NODE_ENV=production browserify . --full-paths | uglifyjs | discify --open", 10 | "size": "npm run build | gzip-size | pretty-bytes" 11 | }, 12 | "author": "Yoshua Wuyts ", 13 | "license": "ISC", 14 | "browserify": { 15 | "transform": [ 16 | "unassertify", 17 | "sheetify/transform", 18 | "hyperxify", 19 | "uglifyify" 20 | ] 21 | }, 22 | "dependencies": { 23 | "hyperx": "^1.0.5", 24 | "sheet-router": "^1.1.0", 25 | "virtual-app": "^2.1.0", 26 | "virtual-dom": "^2.1.1", 27 | "xtend": "^4.0.1" 28 | }, 29 | "devDependencies": { 30 | "browserify": "^13.0.0", 31 | "budo": "^8.0.2", 32 | "disc": "^1.3.2", 33 | "gzip-size-cli": "^1.0.0", 34 | "hyperxify": "^1.1.0", 35 | "pretty-bytes-cli": "^1.0.0", 36 | "uglify-js": "^2.6.1", 37 | "uglifyify": "^3.0.1", 38 | "unassertify": "^2.0.3", 39 | "sheetify": "^4.0.0" 40 | } 41 | } 42 | --------------------------------------------------------------------------------