jumpsuit / jumpsuit
- суббота, 6 августа 2016 г. в 03:19:11
JavaScript
Powerful, efficient front-end framework and CLI, built on React/Redux & the industry's best technologies.
A powerful and extremely efficient Front-end framework & CLI. It is the fastest way to write scalable react/redux apps with the least overhead.
Jumpsuit is still under active development, so any feedback is welcome and appreciated!
Install from NPM
# CLI
$ npm install jumpsuit -g
# Framework Only
$ npm install jumpsuit --save
# Create a new project
$ jumpsuit new myProjectName && cd myProjectName
# Watch for changes
$ jumpsuit watch
# View your project
$ open localhost:8000
<html>
<head>
<title>Jumpsuit Example</title>
</head>
<body>
<div id="app"></div>
<script src="app.js"></script>
</body>
</html>
// Yep, that's all you have to import
import { Render, State, Component } from 'jumpsuit'
// Create a state and with some actions
const CounterState = State('counter', {
// Initial State
initial: { count: 0 },
// Actions
increment (state, payload) {
return { count: ++state.count }
},
decrement (state, payload) {
return { count: --state.count }
},
})
// Create a component
const Counter = Component({
render() {
return (
<div>
<h1>{ this.props.counter.count }</h1>
<button onClick={ () => CounterState.increment() }>Increment</button>
<button onClick={ () => CounterState.decrement() }>Decrement</button>
</div>
)
}
}, (state) => ({
// Subscribe to the counter state (will be available via this.props.counter)
counter: state.counter
}))
// Render your app!
Render({
counter: CounterState
}, <Counter/>)
props
Simple Component
import { Component } from 'jumpsuit'
const SayHello = Component({
render() {
return (
<div>
<button onClick={ this.sayHello }>Say Hello</button>
</div>
)
},
sayHello(){
console.log('Hello!')
},
})
Stateful Component
import { Component } from 'jumpsuit'
const Counter = Component({
render() {
return (
<div>
Count: { this.props.count }
</div>
)
}
// Subscribe to the count property on the count state
}, (state) => {
return {
count: state.counter.count
}
})
Object.assign
on the root object of your returns, but you will however need to maintain immutability for nested properties. If you're not sure what this means, see the state/todos.js
file in the Todo List example for reference.Returns
import { State } from 'jumpsuit'
const CounterState = State({
initial: { count: 0 },
increment (state, payload) {
return { count: ++state.count }
},
set (state, payload) {
return { count: payload }
},
reset (state) {
return { count: 0 }
}
})
// Call the methods normally. No action creators or dispatch required.
CounterState.increment()
// CounterState.getState() === { count: 1 }
CounterState.set(5)
// CounterState.getState() === { count: 5 }
CounterState.reset()
// CounterState.getState() === { count: 0 }
div#app
Parameters
Single State
import { Render } from 'jumpsuit'
import Counter from './containers/counter'
import CounterState from './states/counter'
Render(CounterState, <Counter/>)
Combined State
import { Render } from 'jumpsuit'
import App from './containers/app'
import CounterState from './states/counter'
import TimerState from './states/timer'
const state = {
counter: CounterState, // CounterState's name is 'counter'
timer: TimerState // TimerState's name is 'timer'
}
Render(state, <App/>)
Jumpsuit's built-in router
import { Render, Router, IndexRoute, Route } from 'jumpsuit'
Render(state, (
<Router>
<IndexRoute component={ Home }/>
<Route path="/counter" component={ Counter }/>
</Router>
))
Renders a component at the specified route
import { Render, Router, Route } from 'jumpsuit'
import Counter from './components/counter'
Render(state, (
<Router>
<Route path="/counter" component={ Counter }/>
</Router>
))
Renders a component at the index route of your app
import { Render, Router, Route } from 'jumpsuit'
import Home from './components/home'
Render(state, (
<Router>
<IndexRoute component={ Home }/>
</Router>
))
A method for registering middleware into the underlying redux instance
import { Render, Middleware } from 'jumpsuit'
const myMiddleware = store => next => action => {
let result = next(action)
return result
}
Middleware(myMiddleware, ...OtherMiddleWares)
Render(state, <App/>)
Usage:
jumpsuit <command> [options]
Commands:
new [dir] [example] start a new project at the specified
directory using an optional example template
init [example] start a new project in the current directory
using an optional example template
watch build initial app and wait for file changes
build create a production-ready version of app
serve run the static server
Options:
-p, --port specify the port you want to run on
-h, --host specify the host you want to run on
-v, --version show jumpsuit version number
An optional (but recommended) file at your project's root that can contain any of the following customizations:
// Defaults
module.exports = {
sourceDir: 'src', // Where source files are located
outputDir: 'dist', // Where your built files will be placed
assetsDir: 'assets', // Relative to your sourceDir, everything in here is placed in the root of your outputDir directory.
assetsIgnoreExtensions: [], // If you don't want any files in your assets to copy over, ignore them here. eg ['*.scss']
entry: 'app.js', // Jumpsuit starts building here, relative to your sourceDir
prodSourceMaps: true, // Whether we should output sourcemaps in your production builds
hsr: {
maxAge: 1000, // Max age for Hot State Replacement
shouldCatchErrors: true // Should Hot State replacement catch errors?
},
server: {
host: 'localhost', // The host we serve on when watching
port: 8000, // The port we serve on when watching
},
// More customizations available for browserify
browserify: {
extensions: ['.js'],
rebundles: [],
transforms: [],
globals: {}
},
// Note: By default style hooks are disabled. Standard css files should be placed in your assetsDir
// Style hooks (see Common CSS Configs for example usage)
styles: {
extensions: [], // Extensions of style files in your srcDir that will be watch and passed to the action below on change
action: null // A debounced function that should return all of your css as a string (supports a promise). Debounced by default by 300ms
}
}
jumpsuit.config.js
var fs = require('fs')
var path = require('path')
var stylus = require('stylus')
var nib = require('nib')
module.exports = {
styles: {
extensions: ['.css', '.styl'],
action: buildStyles
}
}
var stylusEntry = path.resolve('src/app.styl')
function buildStyles(){
return new Promise((resolve, reject) => {
stylus.render(fs.readFileSync(stylusEntry, 'utf8'), {
'include css': true,
'hoist atrules': true,
compress: process.env.NODE_ENV === 'production',
paths: [path.resolve('src')],
use: nib()
}, function(err, css){
if (err) reject(err)
resolve(css)
});
})
}
jumpsuit.config.js
var fs = require('fs')
var path = require('path')
var sass = require('node-sass')
module.exports = {
styles: {
extensions: ['.css', '.scss'],
action: buildStyles
}
}
var sassEntry = path.resolve('src/app.styl')
function buildStyles(){
return new Promise((resolve, reject) => {
sass.render({
file: sassEntry,
outputStyle: 'compressed'
}, function(err, res) {
if (err){
return reject(err)
}
resolve(res.css.toString())
});
})
}
Jason Maurer | Tanner Linsley |
MIT © Jumpsuit