Advertisement

Universal JS Applications with React

Front End Architect at Nâu Studio
May. 11, 2017
Advertisement

More Related Content

Advertisement

Universal JS Applications with React

  1. REACTJS UNIVERSAL JS APPLICATION WITH 05/2017
  2. ABOUT ME TRẦN TRỌNG THANH ▸ CTO & Co-founder NauStud.io ▸ 4 years with ActionScript, ex-Pycorian ;) ▸ 5 years with JavaScript ▸ Have worked with ReactJS, Angular 2, and learning VueJS ▸ SaigonJS FB group curator (bit.ly/saigonjs) ▸ Contact: Twitter/Facebook/Github /trongthanh Nau is hiring! 😎❤☕
  3. UNIVERSAL JS APPLICATION WITH REACTJS A BRIEF HISTORY OF WEB APPS ▸ 1992 - Static HTML ▸ 1993 - Server side rendered HTML (CGI protocol) ▸ 1995 - LiveScript (a.k.a JavaScript) in Netscape Nav 2.0 ▸ 1997 - Dynamic HTML, Internet Explorer 4 ▸ 2005 - AJAX web apps ▸ 2010-ish - JS frameworks and Single page apps (SPA)
  4. A BRIEF HISTORY OF WEB APPS WHY SPA? ▸ Instant responses on the UI* ▸ No page refresh, allows page transitions ▸ Less overheads at server side ▸ App-like experience ▸ Foundation for Hybrid mobile apps ▸ More emphasis at Front End, enables back-end-less
  5. A BRIEF HISTORY OF WEB APPS THE ACHILLES’ HILL OF SPA (2015 A.D.) 😞 SEO 😞 First meaningful paint 😞 no-script <!doctype html> <html lang="en"> <head> <title>My Awesome Single Page App</title> <meta charset="utf-8"> <meta name="viewport" content="..."> <link rel="stylesheet" href="styles.min.css"> </head> <body> <div id="root" style="height: 100%"></div> <script src="bundle.js"></script> </body> </html> * Code sample from react-redux-starter-kit
  6. A BRIEF HISTORY OF WEB APPS OBVIOUS SOLUTION? Render content HTML at server-side MORE PROBLEMS? 😞 Duplicated rendering logic at server side 😞 Double work of template maintenance 😞 Flash of updated content 😞 All the relief of SPA for backend is gone
  7. THE RISE OF 
 UNIVERSAL JAVASCRIPT APPLICATIONS
  8. WHAT IS A UNIVERSAL JS APPLICATION? ▸ Used to be called Isomorphic JS Applications ▸ There are portions of JS run on both client and server (hence universal / isomorphic) ▸ Server-side rendered HTML ▸ Server-enabled History Push State
  9. TRADITIONAL SPA WITH REDUX ARCHITECTURE
  10. UNIVERSAL JS APP WITH REDUX ARCHITECTURE
  11. CODE WALKTHROUGH UNIVERSAL REACT APP Based from a simple Universal Redux template
  12. UNIVERSAL - CONTAINER COMPONENT /*...*/ import { connect } from 'react-redux' import { loadQuestionDetail } from 'actions/questions' import { browserHistory } from 'react-router' class Question extends Component { static fetchData({ store, params, history }) { let { id } = params return store.dispatch(loadQuestionDetail({ id, history })) } componentDidMount() { let { id } = this.props.params this.props.loadQuestionDetail({ id, history: browserHistory }) } render() { return (<div> {/* stuff... */}</div>) } } /*...*/ export default connect(mapStateToProps, { loadQuestionDetail })(Question)
  13. SERVER - EXPRESS UNIVERSAL RENDERER MIDDLEWARE import React from 'react' import ReactDOMServer from 'react-dom/server' import { useRouterHistory, RouterContext, match } from 'react-router' import { createMemoryHistory, useQueries } from 'history' import configureStore from 'store/configureStore' import createRoutes from 'routes/index' import { Provider } from 'react-redux' server.get('*', (req, res, next) => { let history = useRouterHistory(useQueries(createMemoryHistory))() let store = configureStore() let routes = createRoutes(history) let location = history.createLocation(req.url) match({ routes, location }, (error, redirectLocation, renderProps) => { /* cont... */ }) }) //end server.get('*')
  14. SERVER - EXPRESS UNIVERSAL RENDERER MIDDLEWARE /*...*/ server.get('*', (req, res, next) => { /* ... */ match({ routes, location }, (error, redirectLocation, renderProps) => { /* handle error & redirectLocation... */ function getReduxPromise() { /*...*/ } getReduxPromise().then(()=> { let reduxState = escape(JSON.stringify(store.getState())) let html = ReactDOMServer.renderToString( <Provider store={store}> { <RouterContext {...renderProps}/> } </Provider> ) let metaHeader = Helmet.rewind() // always render the index template res.render('index', { metaHeader, html, reduxState, scriptSrcs, styleSrc }) }) .catch((err)=> { Helmet.rewind() next(err) }) }) }) //end server.get('*')
  15. SERVER - EXPRESS UNIVERSAL RENDERER MIDDLEWARE function getReduxPromise() { let { query, params } = renderProps let comp = renderProps.components[renderProps.components.length - 1].WrappedComponent let promise = comp.fetchData ? comp.fetchData({ query, params, store, history }) : Promise.resolve() return promise }
  16. SERVER - EXPRESS UNIVERSAL RENDERER MIDDLEWARE /*...*/ server.get('*', (req, res, next) => { /* ... */ match({ routes, location }, (error, redirectLocation, renderProps) => { /* handle error & redirectLocation... */ function getReduxPromise() { /*...*/ } getReduxPromise().then(()=> { let reduxState = escape(JSON.stringify(store.getState())) let html = ReactDOMServer.renderToString( <Provider store={store}> { <RouterContext {...renderProps}/> } </Provider> ) // always render the index template res.render('index', { html, reduxState, /*...*/ }) }) .catch((err)=> { next(err) }) }) }) //end server.get('*')
  17. SERVER - EXPRESS INDEX TEMPLATE <!DOCTYPE html> <html> <head> <%# metaHeader and stylesheet stuff, omit for clarity...%> </head> <body> <div id="root"><%- html %></div> <script type="text/javascript" charset="utf-8"> window.__REDUX_STATE__ = '<%= reduxState %>'; </script> <% scriptSrcs.forEach(function(src){ %> <script src="<%= src %>"></script> <% }) %> </body> </html>
  18. CLIENT - REACT APP.JS /*...*/ import ReactDOM from 'react-dom' import { browserHistory } from 'react-router' import { Provider } from 'react-redux' import createRoutes from 'routes/index' import configureStore from 'store/configureStore' let initialState = {} if (window.__REDUX_STATE__) { try { initialState = JSON.parse(unescape(__REDUX_STATE__)) } catch (e) { /*catch error*/ } } const store = configureStore(initialState) ReactDOM.render(( <Provider store={store}> { createRoutes(browserHistory) } </Provider> ), document.getElementById('root'))
  19. DEMO
  20. UNIVERSAL JS APPLICATION WE HAVE SOLVED: 👍 SEO 👍 First meaningful paint 👍 no-script 👍 Code reuse
  21. WAIT. 
 THERE’S MORE
  22. NEXT.JS INTRODUCING
  23. IN 2 MINUTES LET’S CREATE A UNIVERSAL APP
  24. Q&A
  25. READ MORE REFERENCES ▸ https://medium.com/@mjackson/universal-javascript-4761051b7ae9 ▸ https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js- applications-2bdffbcc1fa0 ▸ https://github.com/mz026/universal-redux-template ▸ https://github.com/erikras/react-redux-universal-hot-example ▸ https://learnnextjs.com
Advertisement