Upload
fitc
View
721
Download
0
Embed Size (px)
Citation preview
– M I K E H O U R A H I N E
“You can learn trigonometry, physics, C++, and DirectX to make a video game. Or you can make a video game and learn DirectX, C++, physics, and
trigonometry.”
A P P # 1 - R E A C T A S A T E M P L AT I N G E N G I N E
• Server side application framework
• Nashorn JavaScript engine for Java 8
• Vert.x 2.3 - Polyglot Event-Driven Messaging
• Innovative Router
• React to describe HTML
A P P # 2 - F L U X
• My first iteration relied on my experience from MVC
• Business logic resides in Models/Stores
• Fat models, skinny controllers
• Models/Stores make AJAX calls
• Actions were very light weight notifications to the Stores
function signInUser(username, password) { Dispatcher.dispatch({ type: ActionTypes.USER_SIGN_IN , username: username , password: password }); }
class UserStore extends EventEmitter { currentUser = null; dispatchToken = Dispatcher.register((action) => { switch(action.type) { case ActionTypes.USER_SIGN_IN: fetchUser(action.username, action.password).then( (response) => { this.currentUser = response.user; this.emit(“change”); }); } }); }
function getState() { return { currentUser: UserStore.currentUser } } class SignInComponent extends React.Component { state = getState(); handleStateChange() { this.setState(getState()); } componentDidMount() { UserStore.on(“change”, this.handleStateChange); } componentWillUnmount() { UserStore.removeListener(“change”, this.handleStateChange); } handleAuth(event) { signInUser(prompt(“What’s your username?”), prompt(“What’s your password?”)); } render() { if(!this.state.currentUser) return <a onClick={this.handleAuth}>Click here to sign in</a>; else return <p>You’re signed in as {this.state.currentUser.name}</p>; } }
A P P # 2 - F L U X - F I R S T I T E R AT I O N
• Facebook’s Dispatcher does not allow you to dispatch from a dispatch
• Difficult to compose application flow
• How do you handle errors?
• Relies on the Global State of ActionTypes
• Views worked great!
class SignInUser extends BaseAction { constructor(username, password, alreadySignedInUser) { this.username = username; this.password = password; this.alreadySignedInUser = alreadySignedInUser; if(!this.alreadySignedInUser) this.authUser(); } authUser() { fetchUser(this.username, this.password).then( (newUser) => { new SignInSuccess(newUser); } , (errors) => { new SignInFailure(errors); } ); }
class SignInUser extends BaseAction { constructor(username, password, alreadySignedInUser) { this.username = username; this.password = password; this.alreadySignedInUser = alreadySignedInUser; if(!this.alreadySignedInUser) this.authUser(); } authUser() { fetchUser(this.username, this.password).then( (newUser) => { new SignInSuccess(newUser); } , (errors) => { new SignInFailure(errors); } ); }
class SignInSuccess extends BaseAction { constructor(newUser) { this.newUser = newUser; this.dispatch(); } }
class SignInFailure extends BaseAction { constructor(errors) { this.errors = errors; this.dispatch();
new FlashMessage(“Could not sign in”); } }
class UserStore extends EventEmitter { currentUser = null; dispatchToken = Dispatcher.register((action) => { switch(action.constructor) { case SignInSuccess: this.currentUser = action.newUser; this.emit(“change”); } }); }
A P P # 2 - F L U X - 2 N D I T E R AT I O N
• Eliminates the “dispatching from a dispatch” problem
• Stores are synchronous
• Very easy to compose the flow of your application by composing actions
• Eliminated Global State of ActionTypes
• Extremely scalable solution
• Easy to test
• In a later iteration, dropped in WebPack
A P P # 3 - B R O C H U R E W E B S I T E
• SEO is paramount
• AJAX is bad for SEO
• Performant on Desktop and Mobile
• Server Side Rendered
• Incremental Loading
• Introduce server side developers to client side technologies
• ES6/ES2015 via Babel
• React + Flux + WebPack
A P P # 3 - B R O C H U R E W E B S I T E
• Server side React + Server side Flux
• WebPack manages front end assets, inlining, and chunking
• Incremental loading by chunking
• Reduce number of web requests by inlining
• Koa.js serves the application and handles routing
G R I F F I N . J S
• Includes everything I’ve learnt and more
• Facebook’s Dispatcher
• React Views
• Griffin Actions - Same as previous examples
• Redux Stores w/ Griffin Connector to Views
class UserStore extends EventEmitter { currentUser = null; dispatchToken = Dispatcher.register((payload) => { switch(payload.constructor) { case SignInSuccess: this.currentUser = payload.newUser; this.emit(“change”); } }); }
class UserStore extends GriffinStore { reducer(state = null, action) => { switch(action.constructor) { case SignInSuccess: return payload.newUser; default: return state; } }); }
function getState() { return { currentUser: UserStore.currentUser } } class SignInComponent extends React.Component { state = getState(); handleStateChange() { this.setState(getState()); } componentDidMount() { UserStore.on(“change”, this.handleStateChange); } componentWillUnmount() { UserStore.removeListener(“change”, this.handleStateChange); } handleAuth(event) { signInUser(prompt(“What’s your username?”), prompt(“What’s your password?”)); } render() { if(!this.state.currentUser) return <a onClick={this.handleAuth}>Click here to sign in</a>; else return <p>You’re signed in as {this.state.currentUser.name}</p>; } }
@connect({ currentUser: UserStore })
class SignInComponent extends React.Component {
handleAuth(event) { signInUser(prompt(“What’s your username?”), prompt(“What’s your password?”)); }
render() {
if(!this.props.currentUser)
return <a onClick={this.handleAuth}>Click here to sign in</a>;
else
return <p>You’re signed in as {this.props.currentUser.name}</p>;
}
}
R E A C T D E P E N D E N C Y I N J E C T I O N
• Using props to pass in external data is similar to Angular’s dependency injection
• Only use state to manage internal component state
• <SignInComponent currentUser={{name: “Mock User!”}} />
• <SignInComponent currentUser={null} />
R E A C T R O U T E R
• Amazing routing solution - Inspired heavily by Ember’s router
• Ember has an excellent router
• Uses JSX or JSON to describe routes and nested routes
• React Component will be loaded by a Route
• Version 1.0 has lazy loading of routes and components
• Better Server Side Rendering
React.render(( <Router> <Route path="/" component={App}> <Route path="about" component={About} /> <Route path="inbox" component={Inbox}> <Route path="messages/:id" component={Message} /> </Route> </Route> </Router> ), document.body)
. ├── AppComponent.js => / ├── AboutComponent.js => /about ├── InboxComponent.js => /inbox └── MessageComponent.js => /inbox/messages/:id
. ├── AppComponent.js => / ├── AboutComponent.js => /about ├── InboxComponent.js => /inbox └── inbox └── MessageComponent.js => /inbox/messages/:id
. ├── index.js => / ├── about │ └── index.js => /about └── inbox ├── index.js => /inbox └── messages └── @id └── index.js => /inbox/messages/:id
. ├── index.js => / ├── about │ └── index.js => /about └── inbox ├── DeleteMessage.js ├── GetMessages.js ├── MessageStore.js ├── index.js => /inbox └── messages └── @id └── index.js => /inbox/messages/:id
React.render(( <Router> <Route path="/" component={App}> <Route path="about" component={About} /> <Route path="inbox" component={Inbox}> <Route path="messages/:id" component={Message} /> </Route> </Route> </Router> ), document.body)
G R I F F I N F I L E S Y S T E M B A S E D R O U T I N G
• Easy to initialize your app
• import myApp from “griffin!.”;myApp({ /* any griffin options here */});
• Easy to mount other apps
• import anotherApp from “griffin!/path/to/app”;anotherApp({ /* griffin options */});
U N I V E R S A L A P P S W I T H W E B PA C K
• Everything goes through WebPack
• Based on James Long’s excellent “Backend Apps with WebPack” posts
• On the server, it ignores CSS, images, etc.
• WebPack enables lazy-loading of application chunks
• Incrementally load Griffin routes
• Include common modules with initial payload
G R I F F I N . J S S TAT U S
• Almost ready for release
• Planning to release in the next few months
• I’m currently rewriting the WebPack incremental file-system based routing
• Last core item remaining before release