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

Universal JavaScript - Frontend United Athens 2017

Universal JavaScript - Frontend United Athens 2017

Since we started to see JS on the server side, the dream of developers has been to reduce the gap and the cost of switch between frontend/backend. Today with Node.js, React and a whole ecosystem of tools, this dream is becoming true! In this talk, I am going to discuss Universal (a.k.a. Isomorphic) JS and present some practical example regarding the major patterns related to routing, data retrieval and rendering. I will use Node, React, Webpack, Babel and React Router and give you a series of example to get you started easily with this new technology trend.

Luciano Mammino

May 29, 2017
Tweet

More Decks by Luciano Mammino

Other Decks in Technology

Transcript

  1. LUCIANO MAMMINO
    UNIVERSAL JAVASCRIPT
    UNIVERSAL JAVASCRIPT
    LUCIANO MAMMINO
    loige.link/athens-2017
    ATHENS, 27 MAY 2017
    1

    View Slide

  2. WHO IS LUCIANO
    lmammino
    loige
    loige.co

    mt. Etna
    Νάξος
    2

    View Slide

  3. NeBK20FUA
    -20% eBook
    NpBK15FUA
    -15% Print
    loige.link/node-book

    ⚡CONTAINS A WHOLE CHAPTER
    ABOUT UNIVERSAL JAVASCRIPT ⚡


    GET A DISCOUNT ​

    3

    View Slide

  4. fullstackbulletin.com
    4

    View Slide



  5. 5

    View Slide

  6. AGENDA
    1. The term "Universal" JS
    2. Who & Why
    3. Common problems and technologies
    4. Building a frontend only Single Page App
    5. Making it "Universal"
    6

    View Slide

  7. ISOMORPHIC
    loige.link/universal-js-story
    UNIVERSAL... WAIT, WHAT?
    7

    View Slide

  8. NOT ONLY
    FOR THE WEB...
    Desktop applications
    Mobile applications
    Hardware!
    8

    View Slide

  9. ADVANTAGES
    OF UNIVERSAL JAVASCRIPT
    "JavaScript-only" development
    Maintainability
    Better SEO
    Faster "perceived" load time
    9

    View Slide

  10. ADVANTAGES...

    MOAR
    Keep using React/JS paradigms also for "static" websites
    Speed up content loading with linkprefetch
    loige.link/universal-react-made-easy-talk
    10

    View Slide

  11. IN THE WILD
    11

    View Slide

  12. IT LOOKS GREAT BUT...
    12

    View Slide

  13. MODULE SHARING
    Use Node.js modules in the browser
    UMD
    13

    View Slide

  14. UNIVERSAL RENDERING
    Render the views of the application from the server (first
    request) and then in the browser (next requests)
    14

    View Slide

  15. UNIVERSAL ROUTING
    Recognise the view associated to the current route from
    both the server and the browser.
    15

    View Slide

  16. UNIVERSAL DATA RETRIEVAL
    Access data (and APIs) from both the server and the browser.
    AXIOS UNIVERSAL
    FETCH
    16

    View Slide

  17. UNIVERSAL STATE MANAGEMENT
    Manage changes on the state tree both on the server and the client...
    17

    View Slide

  18. FUTURISTIC/ALTERNATIVE JS?!
    18

    View Slide

  19. 19

    View Slide

  20. OK...
    LET'S STOP COMPLAINING AND BUILD SOMETHING!
    20

    View Slide

  21. WHAT ARE WE GOING TO BUILD?
    loige.link/judo-heroes-app​
    loige.link/judo-heroes-tutorial
    v 2.0
    21

    View Slide

  22. 22

    View Slide

  23. 23

    View Slide

  24. 24

    View Slide

  25. curl -sS "http://localhost:3000/athlete/teddy-riner"
    25

    View Slide

  26. WHAT TOOLS ARE WE GOING TO USE?
    v2 v15.4
    v4
    v5-alpha
    26

    View Slide

  27. View Slide

  28. 28

    View Slide

  29. The data set
    // src/data/athletes.js
    const athletes = [
    {
    id: 'driulis-gonzalez',
    name: 'Driulis González',
    country: {
    id: 'cu',
    name: 'Cuba',
    icon: 'flag-cu.png',
    },
    birth: '1973',
    image: 'driulis-gonzalez.jpg',
    cover: 'driulis-gonzalez-cover.jpg',
    link: 'https://en.wikipedia.org/wiki/Driulis_González',
    medals: [
    { id: 1, year: '1992', type: 'B', city: 'Barcelona', event: 'Olympic Games', category: '-57kg' },
    { id: 2, year: '1993', type: 'B', city: 'Hamilton', event: 'World Championships', category: '-57kg' },
    { id: 3, year: '1995', type: 'G', city: 'Chiba', event: 'World Championships', category: '-57kg' },
    { id: 4, year: '1995', type: 'G', city: 'Mar del Plata', event: 'Pan American Games', category: '-57kg' },
    { id: 5, year: '1996', type: 'G', city: 'Atlanta', event: 'Olympic Games', category: '-57kg' },
    // ...
    ],
    },
    // ...
    ];
    export default athletes;
    29

    View Slide

  30. REACT COMPONENTS
    30

    View Slide

  31. Layout component
    31

    View Slide

  32. IndexPage component
    32

    View Slide

  33. AthletePage component
    33

    View Slide

  34. NotFoundPage component
    34

    View Slide

  35. AthletePreview component
    35

    View Slide

  36. AthletesMenu component
    36

    View Slide

  37. Flag component
    37

    View Slide

  38. Medal component
    38

    View Slide

  39. // src/components/Layout.js
    import React from 'react';
    import { Link } from 'react-router-dom';
    export const Layout = props => (






    {props.children}


    This is a demo app to showcase
    universal Javascript
    with React and
    Express.



    );
    export default Layout;
    39

    View Slide

  40. // src/components/IndexPage.js
    import React from 'react';
    import { AthletePreview } from './AthletePreview';
    export const IndexPage = ({ athletes }) => (


    {
    athletes.map( athleteData =>
    key={athleteData.id}
    {...athleteData} />
    )
    }


    );
    export default IndexPage;
    40

    View Slide

  41. // src/components/AthletePreview.js
    import React from 'react';
    import { Link } from 'react-router';
    export const AthletePreview = (props) => (



    {props.name}

    {props.medals.length}



    );
    export default AthletePreview;
    41

    View Slide

  42. ROUTING
    42

    View Slide

  43. 2 ROUTES
    Index Page: /
    Athlete Page: /athlete/:id
    43

    View Slide

  44. // src/components/App.js
    import React from 'react';
    import { Route, Switch } from 'react-router-dom';
    import { Layout } from './Layout';
    import { IndexPage } from './IndexPage';
    import { AthletePage } from './AthletePage';
    import { NotFoundPage } from './NotFoundPage';
    import athletes from '../data/athletes';
    // ...
    export const App = () => (







    );
    export default App; 44

    View Slide

  45. // src/components/App.js
    // ...
    const renderIndex = () => ;
    const renderAthlete = ({ match, staticContext }) => {
    const id = match.params.id;
    const athlete = athletes.find(current => current.id === id);
    if (!athlete) {
    return ;
    }
    return athlete={athlete}
    athletes={athletes} />;
    };
    45

    View Slide

  46. CLIENT APP
    46

    View Slide

  47. // src/app-client.js
    import React from 'react';
    import { render } from 'react-dom';
    import { BrowserRouter as Router } from 'react-router-dom';
    import { App } from './components/App';
    const AppClient = () => (



    );
    window.onload = () => {
    render(
    ,
    document.getElementById('main')
    );
    };
    47

    View Slide

  48. HTML TEMPLATE
    48

    View Slide

  49. // src/views/index.ejs




    content="width=device-width, initial-scale=1.0">

    Judo Heroes - A Universal JavaScript demo application with React




    <%- markup -%>



    49

    View Slide

  50. BUILD CONFIG
    (BABEL + WEBPACK)
    50

    View Slide

  51. .babelrc
    import path from 'path';
    const config = {
    entry: {
    js: './src/app-client.js',
    },
    output: {
    path: path.join(__dirname, 'src', 'static', 'js'),
    filename: 'bundle.js',
    },
    module: {
    rules: [
    {
    test: path.join(__dirname, 'src'),
    use: { loader: 'babel-loader' },
    },
    ],
    },
    };
    export default config;
    .webpack.config.babel.js
    {
    "presets": ["react", "es2015"]
    }
    51

    View Slide

  52. LET'S BUILD IT!
    52

    View Slide

  53. // src/server.js
    import path from 'path';
    import { Server } from 'http';
    import Express from 'express';
    const app = new Express();
    const server = new Server(app);
    // use ejs templates
    app.set('view engine', 'ejs');
    app.set('views', path.join(__dirname, 'views'));
    // define the folder that will be used for static assets
    app.use(Express.static(path.join(__dirname, 'static')));
    // render the index for every non-matched route
    app.get('*', (req, res) => {
    let markup = '';
    let status = 200;
    return res.status(status).render('index', { markup });
    });
    // start the server
    const port = process.env.PORT || 3000;
    const env = process.env.NODE_ENV || 'production';
    server.listen(port);
    "Static" Express server
    53

    View Slide

  54. READY... LET'S TEST IT
    54

    View Slide

  55. RECAP
    What we learned so far
    1. Define views combining React components
    2. Add routing using React Router
    3. Compile the client bundle with Babel and Webpack
    4. Run the app with a static Express server
    55

    View Slide

  56. SERVER SIDE
    RENDERING AND ROUTING
    56

    View Slide

  57. Updating the server app
    // ...
    import { renderToString } from 'react-dom/server';
    import { StaticRouter as Router } from 'react-router-dom';
    import { App } from './components/App';
    // ...
    app.get('*', (req, res) => {
    let markup = '';
    let status = 200;
    const context = {};
    markup = renderToString(


    ,
    );
    // context.url will contain the URL to
    // redirect to if a was used
    if (context.url) {
    return res.redirect(302, context.url);
    }
    if (context.is404) {
    status = 404;
    }
    return res.status(status).render('index', { markup });
    });
    57

    View Slide

  58. THAT'S IT!
    LET'S TEST AGAIN
    58

    View Slide

  59. RECAP
    What we learned so far
    1. Create a Single Page Application with React and React Router
    2. Add server side routing and rendering using React and React
    Router libraries in the Express app
    59

    View Slide

  60. UNIVERSAL DATA RETRIEVAL
    api-proxy & async-props
    (COMPLETE CHAPTER in )
    UNIVERSAL STATE MANAGEMENT
    Redux
    PROGRESSIVE WEB APPS (PWA)
    +
    Node.js Design Patterns
    @addyosmani's tutorial Create React App
    WHERE DO WE GO
    from here...
    Code: loige.link/judo-heroes-2
    60

    View Slide

  61. THANKS!
    loige loige.co
    lmammino
    (Special thanks to , , Aleksandar Čambas & )
    @cirpo @andreaman87 @quasi_modal
    loige.link/athens-2017​
    61

    View Slide