Simple universal React apps with Next.js

"By universal, I mean that it works everywhere."

 

- Guillermo Rauch, creator of several popular Node.JS open source libraries like socket.io, mongoose and slackin.  Founder of ZEIT.

 

Server side rendering (SSR)?

  • It's "Faster"
  • Better SEO

Pros

Faster initial load

 

Better SEO

Cons

Slower TTFB

(Time to first byte)

 

Greater Complexity

Pros

Faster initial load

 

Better SEO

Cons

Slower TTFB

(Time to first byte)

 

Greater Complexity

https://medium.com/walmartlabs/the-benefits-of-server-side-rendering-over-client-side-rendering-5d07ff2cefe8


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <!--
      manifest.json provides metadata used when your web app is added to the
      homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
    -->
    <link rel="manifest" href="/manifest.json">
    <link rel="shortcut icon" href="/favicon.ico">
    <!--
      Notice the use of  in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  <script type="text/javascript" src="/static/js/bundle.js"></script></body>
</html>
<!DOCTYPE html>
<html>

<head>
    <meta charSet="utf-8" class="next-head" />
    <link rel="preload" href="/_next/9a92b3b0-d779-4754-83ba-bf499bdbcd93/page/index.js" as="script" />
    <link rel="preload" href="/_next/9a92b3b0-d779-4754-83ba-bf499bdbcd93/page/_error.js" as="script" />
    <link rel="preload" href="/_next/c3ecb62c24f9c6290c07c14368b96e2f/app.js" as="script" />
</head>

<body>
    <div>
        <div id="__next">
            <div data-reactroot="">
                <div>
                    <h1>Next Chefs</h1>
                    <div><a href="/episode?id=tt4383018">Massimo Bottura</a></div>
                    <div><a href="/episode?id=tt4360158">Dan Barber</a></div>
                    <div><a href="/episode?id=tt4360152">Francis Mallmann</a></div>
                    <div><a href="/episode?id=tt4338616">Niki Nakayama</a></div>
                    <div><a href="/episode?id=tt4338608">Ben Shewry</a></div>
                    <div><a href="/episode?id=tt4360160">Magnus Nilsson</a></div>
                </div>
            </div>
        </div>
        <div id="__next-error"></div>
    </div>
    <div>
        <script>
            __NEXT_DATA__ = {
                "props": {
                    "series": {
                        "Title": "Chef's Table",
                        "Season": "1",
                        "totalSeasons": "3",
                        "Episodes": [{
                            "Title": "Massimo Bottura",
                            "Released": "2015-04-26",
                            "Episode": "1",
                            "imdbRating": "8.5",
                            "imdbID": "tt4383018"
                        }, {
                            "Title": "Dan Barber",
                            "Released": "2015-02-12",
                            "Episode": "2",
                            "imdbRating": "7.7",
                            "imdbID": "tt4360158"
                        }, {
                            "Title": "Francis Mallmann",
                            "Released": "2015-04-26",
                            "Episode": "3",
                            "imdbRating": "8.3",
                            "imdbID": "tt4360152"
                        }, {
                            "Title": "Niki Nakayama",
                            "Released": "2015-04-26",
                            "Episode": "4",
                            "imdbRating": "8.0",
                            "imdbID": "tt4338616"
                        }, {
                            "Title": "Ben Shewry",
                            "Released": "2015-04-26",
                            "Episode": "5",
                            "imdbRating": "7.7",
                            "imdbID": "tt4338608"
                        }, {
                            "Title": "Magnus Nilsson",
                            "Released": "2015-04-26",
                            "Episode": "6",
                            "imdbRating": "8.5",
                            "imdbID": "tt4360160"
                        }],
                        "Response": "True"
                    }
                },
                "pathname": "/",
                "query": {},
                "buildId": "9a92b3b0-d779-4754-83ba-bf499bdbcd93",
                "buildStats": {
                    "app.js": {
                        "hash": "c3ecb62c24f9c6290c07c14368b96e2f"
                    }
                },
                "assetPrefix": "",
                "nextExport": false,
                "err": null,
                "chunks": []
            }
            module = {}
            __NEXT_LOADED_PAGES__ = []
            __NEXT_LOADED_CHUNKS__ = []

            __NEXT_REGISTER_PAGE = function(route, fn) {
                __NEXT_LOADED_PAGES__.push({
                    route: route,
                    fn: fn
                })
            }

            __NEXT_REGISTER_CHUNK = function(chunkName, fn) {
                __NEXT_LOADED_CHUNKS__.push({
                    chunkName: chunkName,
                    fn: fn
                })
            }
        </script>
        <script async="" id="__NEXT_PAGE__/" type="text/javascript" src="/_next/9a92b3b0-d779-4754-83ba-bf499bdbcd93/page/index.js"></script>
        <script async="" id="__NEXT_PAGE__/_error" type="text/javascript" src="/_next/9a92b3b0-d779-4754-83ba-bf499bdbcd93/page/_error.js"></script>
        <div></div>
        <script type="text/javascript" src="/_next/c3ecb62c24f9c6290c07c14368b96e2f/app.js" async=""></script>
    </div>
</body>

</html>

Why Next.js?

  • Automatic code splitting
  • Page based routing
  • Sensible defaults
  • Easily Customizable
  • Good developer experience.  Short README.  HMR.

*pages/ - Points of entry

 

lib/ - data-fetching and helpers

 

components/ - Standalone components

 

static/ - Static assets

App Structure

Router

Link allows you to "prefetch" routes

 

Exposes router HOC (Higher order component)

 

Custom server routes

 

 

 

 

getInitialProps

  • Only used in pages
  • Returns data to populate props
  • Can be used in stateless pages
  • Executes on the server for the initial page load, then on client when routing.
const Page = ({ stars }) =>
  <div>
    Next stars: {stars}
  </div>

Page.getInitialProps = async ({ req }) => {
  const res = await fetch('https://api.github.com/repos/zeit/next.js')
  const json = await res.json()
  return { stars: json.stargazers_count }
}

export default Page

Resources

https://medium.com/walmartlabs/the-benefits-of-server-side-rendering-over-client-side-rendering-5d07ff2cefe8

 

https://css-tricks.com/server-side-react-rendering/

 

https://github.com/zeit/next.js/

 

https://learnnextjs.com/

 

Simple Universal React Apps with Next.js

By louisnovick

Simple Universal React Apps with Next.js

  • 300