Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Universal and Progressive Web Apps with ReactJS

Avatar for Mike Bild Mike Bild
November 26, 2017

Universal and Progressive Web Apps with ReactJS

Avatar for Mike Bild

Mike Bild

November 26, 2017
Tweet

More Decks by Mike Bild

Other Decks in Programming

Transcript

  1. UNIVERSAL WEB APP + REACTJS TODAY ▸ Web-Development ▸ Universal

    Web Apps + ReactJS ▸ Demo ▸ Resources ▸ Bonus
  2. UNIVERSAL WEB APP + REACTJS DECADES OF WEB-DEVELOPMENT ▸ Server

    Side Rendering ▸ Single Page Apps ▸ Universal Web Apps ▸ Progressive Web Apps ▸ Demo
  3. UNIVERSAL WEB APP + REACTJS SERVER-SIDE-RENDERING (CLASSIC) ▸ Facebook, GitHub

    etc. - great success stories ▸ Perl / PHP / Rails & more MVC Frameworks ▸ Many Round-Trips ▸ Mixed Code & Structure
  4. UNIVERSAL WEB APP + REACTJS SINGLE PAGE APP (CLIENT RENDERING)

    Empty
 index.html <script src>
 </script> JS React
 execution Page
 interaction
  5. UNIVERSAL WEB APP + REACTJS SPA - RECAP ▸ SEO

    ▸ Routing ▸ JavaScript / Web Security ▸ Initial data fetching ++ - - ▸ Logged in User Context ▸ Static WebSite Deployment ▸ Scalability
  6. UNIVERSAL WEB APP + REACTJS UNIVERSAL WEB APP (SERVER +

    CLIENT RENDERING) SSR <script src>
 </script> JS React
 execution Page
 interaction
  7. UNIVERSAL WEB APP + REACTJS UWA - RECAP ▸ Slower

    Time To First Byte ▸ Server Runtime ▸ Scalability ++ - - ▸ Logged out User Context ▸ Rendered earlier ▸ Less page flicker ▸ JavaScript / Web Security
  8. UNIVERSAL WEB APP + REACTJS NEXT? PROGRESSIVE WEB APPLICATIONS ▸

    HTTPS + Service-Worker ▸ Faster content more reliable (prefetch, cache, offline) ▸ Environment integration (Homescreen, Push-Notifications) ▸ Tooling (Googles Lighthouse) ▸ Browsers?
  9. UNIVERSAL WEB APP + REACTJS @REACT16 + SERVER SIDE RENDERER

    ▸ Simplified and more Efficient ▸ ReactDOM.hydrate - no checksum markup validation ▸ ReactDOM.renderToNodeStream - async Renderer
  10. UNIVERSAL WEB APP + REACTJS UWA FLOW Shared JavaScript /

    ES6 / ES7
 ReactJS Component ./dist/client.js WebPack.Client.Config NodeJS
 router.get(/, …) {renderToString} from 'react-dom/server' index.html WebPack.Server.Config {renderToNodeStream} from 'react-dom/server' @REACT15 / @REACT16
  11. UNIVERSAL WEB APP + REACTJS NEXT? PROGRESSIVE WEB APPLICATIONS PREFETCH

    RESOURCES CACHE ASSETS OFFLINE ACCESS PUSH NOTIFICATIONS
  12. UNIVERSAL WEB APP + REACTJS RESOURCE PREFETCH + CACHE ASSETS

    var CACHE_NAME = 'pwa-cache-v__TIMESTAMP__'; self.addEventListener('activate', event => { var cacheWhitelist = [CACHE_NAME]; event.waitUntil( caches.keys().then(keyList => Promise.all( keyList.map(key => { if (!cacheWhitelist.includes(key)) { console.log(`Deleting cache: ${key}`); return caches.delete(key); } }) ) ) ); }); self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME).then(cache => fetch('assets-manifest.json', {headers: {'Content-Type': 'application/json'}}) .then(res => res.json()) .then(assets => cache.addAll(assets)) .then(() => console.log('Cached')) ) ); }); self.addEventListener('fetch', function(event) { event.respondWith(caches.match(event.request).then(response => response || fetch(event.request))); }); CACHE TIMESTAMP SERVICE WORKER
  13. UNIVERSAL WEB APP + REACTJS ASSETS-MANIFEST (JSON) [ "/", "/main.js",

    "/main.css", "/logo.png", "https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,300,400italic,600,200,600italic,700,900", "https://fonts.gstatic.com/s/sourcesanspro/v10/ODelI1aHBYDBqgeIAH2zlJbPFduIYtoLzwST68uhz_Y.woff2", "https://fonts.gstatic.com/s/sourcesanspro/v10/toadOcfmlt9b38dHJxOBGJkF8H8ye47wsfpWywda8og.woff2", "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css", "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/fonts/fontawesome-webfont.woff2?v=4.6.3", "https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css" ] CONFIGURABLE ASSET AND RESOURCE LIST
  14. UNIVERSAL WEB APP + REACTJS PWA-APP-MANIFEST { "name": "UWA-PWA", "short_name":

    "UWA-PWA", "start_url": "/?homescreen=1", "display": "standalone", "theme_color": "aliceblue", "background_color": "gray", "description": "My React-Universal-App", "icons": [{ "src": "homescreen.png", "sizes": "48x48", "type": "image/png" }], "related_applications": [{ "platform": "web", "id": "UWA-PWA" }] } ADD TO HOMESCREEN SPLASHSCREEN
  15. UNIVERSAL WEB APP + REACTJS SERVER import express from 'express'

    const app = express() app.use(express.static(__dirname + '/statics')) app.listen(8080, () => console.log(`Listen on 8080`)) NODEJS + EXPRESSJS + @REACT15 / REACT16
  16. UNIVERSAL WEB APP + REACTJS COMPONENTS import React from 'react'

    export default class HelloWorld extends React.PureComponent { render() { return ( <div>Hello, {this.props.greeting}</div> ) } } @REACT15 / @REACT16
  17. UNIVERSAL WEB APP + REACTJS SERVER + REACT import React

    from 'react' import {renderToString} from 'react-dom/server' import HelloWorld from ‚../components/HelloWorld' app.get('/', (req, res) => { const initialData = 'Universal Web App' const html = renderToString(<HelloWorld />) res.send(renderUniversalPageWithData(html, initialData)) }) @REACT15
  18. UNIVERSAL REACTJS SERVER HTML TEMPLATE function renderUniversalPageWithData(html, initialData) { return

    ( `<html> <head lang="de"> <meta charset="UTF-8"> <title>ReactJS SSR</title> </head> <body> <div id="root">${html}</div> </body> <script> window.__INITIAL_STATE__ = ${JSON.stringify(initialData)}; </script> <script src="/bundle.js"></script> </html>` ) } @REACT15
  19. UNIVERSAL WEB APP + REACTJS SERVER + REACT import React

    from 'react' import {renderToNodeStream} from 'react-dom/server' import HelloWorld from '../components/HelloWorld' app.get('/', (req, res) => { renderToNodeStream( <Html initialData={JSON.stringify(initialData)}> <HelloWorld {...initialData} /> </Html> ).pipe(res); }) @REACT16
  20. UNIVERSAL REACTJS SERVER HTML TEMPLATE import React from 'react' const

    Html = props => ( <html> <head> <title>ReactJS SSR</title> </head> <body> <div id="root">{props.children}</div> <script id="initial-data" type="text/plain" data-json={props.initialData} /> <script src="/bundle.js" /> </body> </html> ) export default Html @REACT16
  21. UNIVERSAL WEB APP + REACTJS CLIENT import React from 'react'

    import {render} from 'react-dom' import HelloWorld from ‚../components/HelloWorld' const initialData = window.__INITIAL_STATE__ render( <HelloWorld {...initialData} />, document.getElementById('root') ) @REACT15
  22. UNIVERSAL WEB APP + REACTJS CLIENT import React from 'react'

    import {hydrate} from 'react-dom' import HelloWorld from '../components/HelloWorld' const initialData = JSON.parse( document.getElementById('initial-data').getAttribute('data-json') ) hydrate( <HelloWorld {...initialData} />, document.getElementById('root') ) @REACT16
  23. UNIVERSAL WEB APP + REACTJS UWA + REACT ROUTER4 ▸

    Server - StaticRouter ▸ Client - BrowserRouter ▸ Routes
  24. UNIVERSAL WEB APP + REACTJS THANK YOU! QUESTIONS SOFTWARE ENGINEER


    // FREELANCER // WORKSHOPS @MIKEBILD @MIKEBILD ASK ME ABOUT UWA & PWA
  25. UNIVERSAL WEB APP + REACTJS RESOURCES ▸ Reunify UWA +

    PWA https://www.reunify.run ▸ Reunify Code and Issues on GitHub https://github.com/CodeCommission/reunify ▸ Reunify News on Twitter https://twitter.com/reunify_run