React Loadable: Code Splitting with Server Side Rendering

Similar documents
React + React Native. Based on material by Danilo Filgueira

React. SWE 432, Fall Web Application Development

React & Redux in Hulu. (Morgan Cheng)

React(.js) the Domino Way High-Performance Client for Domino. Knut Herrmann

React.js. a crash course. Jake Zimmerman January 29th, 2016

Frontend Frameworks Part 2. SWE 432, Fall 2017 Design and Implementation of Software for the Web

Gearing Up for Development CS130(0)

Xtern BOOTCAMP. Week 2 Day 1 May 22, 2017

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. ReactJS

React native. State An overview. See the tutorials at

REDUX: FP FOR THE WEB

React Not Just Hype!

Lecture 8. ReactJS 1 / 24

Getting Started with ReactJS

React. HTML code is made up of tags. In the example below, <head> is an opening tag and </head> is the matching closing tag.

Advanced React JS + Redux Development

Table of Contents

Full Stack boot camp

State Management and Redux. Shan-Hung Wu & DataLab CS, NTHU

Hacking with React. Get started with React, React Router, Jest, Webpack, ES6 and more with this hands-on guide. Paul Hudson.

Templates and Databinding. SWE 432, Fall 2017 Design and Implementation of Software for the Web

React tips. while building facebook-scale application

What is Node.js? Tim Davis Director, The Turtle Partnership Ltd

Manual Html A Href Onclick Submit Form

CS193X: Web Programming Fundamentals

ethnio tm IMPLEMENTATION GUIDE ETHNIO, INC W SUNSET BLVD LOS ANGELES, CA TEL (888) VERSION NO. 3 CREATED JUL 14, 2017

Building with React Native. Simon Ayzman Mobile Apps Bloomberg

Lesson: Web Programming(6) Omid Jafarinezhad Sharif University of Technology

Arjen de Blok. Senior Technical Consultant bij ICT Groep ( sinds 1995 Programmeren sinds 1990 Technologiën. Links

Pro MERN Stack. Full Stack Web App Development with Mongo, Express, React, and Node. Vasan Subramanian

Full Stack Developer with Java

Jeff Barczewski. US Air Force Married. Catholic. RGA Father. Consultant Aerospace Engineer. 27 years as professional developer

Web Development for Dinosaurs An Introduction to Modern Web Development

1 CS480W Quiz 6 Solution

React Native. Shan-Hung Wu & DataLab CS, NTHU

Stencil: The Time for Vanilla Web Components has Arrived

#06 RPC & REST CLIENT/SERVER COMPUTING AND WEB TECHNOLOGIES

Frontend UI Training. Whats App :

Building Native Mapping Apps with PhoneGap: Advanced Techniques Andy

High Performance Single Page Application with Vue.js

DECOUPLING PATTERNS, SERVICES AND CREATING AN ENTERPRISE LEVEL EDITORIAL EXPERIENCE

Think like an Elm developer

Reagent. a ClojureScript interface to React. React Amsterdam Meetup 12 Feb. 2015

AngularJS Fundamentals

Sweet Themes Are Made of This: The Magento PWA Studio

Down With JavaScript!

Building an OpenLayers 3 map viewer with React

Angular 4 Syllabus. Module 1: Introduction. Module 2: AngularJS to Angular 4. Module 3: Introduction to Typescript

Backend Development. SWE 432, Fall Web Application Development

Quick Desktop Application Development Using Electron

The tech behind a design system that scales

Future Web App Technologies

6 th October 2018 Milan

6 JAVASCRIPT PROJECTS

ReactJS and Webpack for Rails

A Guide to Liv-ex Software Development Kit (SDK)

Ten interesting features of Google s Angular Project

NoSQL & Firebase. SWE 432, Fall Web Application Development

Approaches to wrapping React. Thursday 3 September 15

Webpack. What is Webpack? APPENDIX A. n n n

Migrating from Flux to Redux

Extending Blue Ocean Keith Zantow

profiling Node.js applications

ethnio tm Technical Overview VERSION NO. 6 CREATED AUG 22, 2018 ETHNIO, INC W SUNSET BLVD LOS ANGELES, CA TEL (888)

CSC 405 Computer Security. Web Security

Makbul Khan. Nikhil Sukul

Oracle SQL Developer & REST Data Services

React Native. Animation

Evolution of the "Web

RequireJS Javascript Modules for the Browser. By Ben Keith Quoin, Inc.

Vue.js Developer friendly, Fast and Versatile

JavaScript Rd2. -Kyle Simpson, You Don t Know JS

"Charting the Course... Comprehensive Angular. Course Summary

Web Performance in

Outline. MXCuBE3 at ESRF. Remote Access. Quick Review of 3.0. New in version Future work. Marcus Oskarsson

AngularJS AN INTRODUCTION. Introduction to the AngularJS framework

Say No to Complexity!

Catbook Workshop 1: Client Side JS. Danny Tang

AEM React. History. 1 Introduction. AEM components written in React. Why React and AEM? Features. Projects. date author message changed chapters

iframe programming with jquery jquery Summit 2011

jquery and AJAX

MARIA KERN NETZ98 GMBH MAGENTO 2 UI COMPONENTS THE JS PART

CS193X: Web Programming Fundamentals

Client Side JavaScript and AJAX

JavaScript: Introduction, Types

Frontend Frameworks. SWE 432, Fall 2016 Design and Implementation of Software for the Web

MEAN Stack. 1. Introduction. 2. Foundation a. The Node.js framework b. Installing Node.js c. Using Node.js to execute scripts

React Native. HTTP/Fetch Sending data

Overview... 4 JavaScript Charting and Metric Insights... 5

The starter app has a menu + 2 Views : Dashboard. About

v0.9.3 Tim Neil Director, Application Platform & Tools Product

webpack bundle inner structure and optimization Alexey Ivanov, Evil Martians

Supercharge your next web app with Electron!

FITECH FITNESS TECHNOLOGY

Writing Modular Stylesheets With CSS Modules.

MANNING. Universal development with React SAMPLE CHAPTER. Elyse Kolker Gordon

Catbook Workshop: Intro to NodeJS. Monde Duinkharjav

Site Speed: To Measure Is To Know. Sava Sertov QA Technical Lead ecommera

Integrating Angular with ASP.NET Core RESTful Services. Dan Wahlin

Quest: Choose the ideal web platform for your business

Transcription:

React Loadable: Code Splitting with Server Side Rendering

About me Former Senior Frontend Developer at Oppex Tech Lead at Toughbyte Ltd React github.com/northerneyes medium.com/@northerneyes twitter.com/nordfinn

Agenda Problem statement Code-Splitting Server Side Rendering Code-Splitting + Server Side Rendering Universal Data Fetching

Big applications

Loading time is big

Why is it important?

Usability

Performance

HTTP2

Solution: Code Splitting

What is it?

Instruments: &

Demo

Route-based splitting vs Component-based splitting

We can do better

Component-based splitting

What is advantage?

More places to split apart our app: Modals Tabs Some hidden content And many more UI

But you can use routing as well

React Loadable

What is React Loadable?

Small library created by @thejameskyle Loadable is Higher-Order Component (HoC)

Example import AnotherComponent from './another-component'; class MyComponent extends React.Component { render() { return <AnotherComponent/>; } }

AnotherComponent being imported synchronously via import

Let s make it loaded asynchronously class MyComponent extends React.Component { state = { AnotherComponent: null }; } componentwillmount() { import('./another-component').then(anothercomponent => { this.setstate({ AnotherComponent }); }); } render() { let {AnotherComponent} = this.state; if (!AnotherComponent) { return <div>loading...</div>; } else { return <AnotherComponent/>; }; }

A bunch of manual work

Loadable is simple

class MyComponent extends React.Component { render() { return <LoadableAnotherComponent/>; } } Loadable import Loadable from 'react-loadable'; function MyLoadingComponent() { return <div>loading...</div>; } const LoadableAnotherComponent = Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent });

What about error handling?

Error handling is simple function MyLoadingComponent({ error }) { if (error) { return <div>error!</div>; } else { return <div>loading...</div>; } }

Automatic code-splitting on import()

Thanks to

Demo

Avoiding Flash Of Loading Component

Do you remember the first slide?

Avoiding Flash Of Loading Component export default function MyLoadingComponent({ error, pastdelay }) { if (error) { return <div>error!</div>; } else if (pastdelay) { return <div>loading...</div>; } else { return null; } }

Easy to change delay parameter Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent, delay: 300 });

What else we can do?

What about Preloading?

Preloading let LoadableMyComponent = Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent, }); class MyComponent extends React.Component { state = { showcomponent: false }; } onclick = () => { this.setstate({ showcomponent: true }); }; onmouseover = () => { LoadableMyComponent.preload(); }; render() { return ( <div> <button onclick={this.onclick} onmouseover={this.onmouseover}> Show loadable component </button> {this.state.showcomponent && <LoadableMyComponent/>} </div> ) }

Server Side Rendering

What is Isomorphic Rendering?

Rendering the web app on server and sending the complete HTML to the client.

The client creates the HTML in memory(virtual Dom), checks if there are changes and re-renders the page on client.

Advantages

Better UX as user gets the complete page on first hit to the server.

Everybody like this picture :)

Better SEO as the bots can easily index the pages

Let s make google happy

Server Side Rendering with React is easy

React Server Rendering import ReactDOMServer from 'react-dom/server'; ReactDOMServer.renderToString( <Provider store={store}> <StaticRouter location={req.url} context={{}}> <App /> </StaticRouter> </Provider>, );

Code-splitting + Server rendering

From react-router page: We ve tried and failed a couple of times. What we learned: You need synchronous module resolution on the server so you can get those bundles in the initial render. You need to load all the bundles in the client that were involved in the server render before rendering so that the client render is the same as the server render. (The trickiest part, I think its possible but this is where I gave up.) You need asynchronous resolution for the rest of the client app s life.

How we can solve these problems?

Let s go back to React Loadable

class MyComponent extends React.Component { render() { return <LoadableAnotherComponent/>; } } Loadable import Loadable from 'react-loadable'; function MyLoadingComponent() { return <div>loading...</div>; } const LoadableAnotherComponent = Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent });

From react-router page: We ve tried and failed a couple of times. What we learned: You need synchronous module resolution on the server so you can get those bundles in the initial render. You need to load all the bundles in the client that were involved in the server render before rendering so that the client render is the same as the server render. (The trickiest part, I think its possible but this is where I gave up.) You need asynchronous resolution for the rest of the client app s life.

From react-router page: We ve tried and failed a couple of times. What we learned: You need synchronous module resolution on the server so you can get those bundles in the initial render. You need to load all the bundles in the client that were involved in the server render before rendering so that the client render is the same as the server render. (The trickiest part, I think its possible but this is where I gave up.) You need asynchronous resolution for the rest of the client app s life.

Synchronous module resolution on the server

Synchronous loading for the server import path from 'path'; const LoadableAnotherComponent = Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent, delay: 200, serversiderequirepath: path.join( dirname, './another-component') });

From react-router page: We ve tried and failed a couple of times. What we learned: You need synchronous module resolution on the server so you can get those bundles in the initial render. You need to load all the bundles in the client that were involved in the server render before rendering so that the client render is the same as the server render. (The trickiest part, I think its possible but this is where I gave up.) You need asynchronous resolution for the rest of the client app s life.

From react-router page: We ve tried and failed a couple of times. What we learned: You need synchronous module resolution on the server so you can get those bundles in the initial render. You need to load all the bundles in the client that were involved in the server render before rendering so that the client render is the same as the server render. (The trickiest part, I think its possible but this is where I gave up.) You need asynchronous resolution for the rest of the client app s life.

Yes, This is the most complicated

We need 2 things

webpack --json > output-webpack-stats.json

Webpack stats about our bundle let webpackstats = require('./output-webpack-stats.json'); let modules = {}; let bundles = {}; webpackstats.modules.foreach(module => { let parts = module.identifier.split('!'); let filepath = parts[parts.length - 1]; modules[filepath] = module.chunks; }); webpackstats.chunks.foreach(chunk => { bundles[chunk.id] = chunk.files; });

And special function flushserversiderequires from react-loadable import {flushserversiderequires} from 'react-loadable'; let app = ReactDOMServer.renderToString(<App/>); let requires = flushserversiderequires(); let scripts = ['bundle-main.js']; requires.foreach(file => { let matchedbundles = modules[file + '.js']; matchedbundles.foreach(bundle => { bundles[bundle].foreach(script => { scripts.unshift(script); }); }); });

And the result res.send(` <!doctype html> <html> <head> <meta charset="utf-8"> <title>react-loadable-example</title> </head> <body> <div id="root">${app}</div> ${scripts.map(script => { return `<script type="text/javascript" src="scripts/${script}"></script>` }).join('\n')} </body> </html> `) })

Demo

Universal Data Fetching (Redux)

Fetching is simple class News extends React.Component { constructor(props) { super(props); props.getnews(); } render() { const { items } = this.props.news; } } return (... );

High order function export default function fetch(fn) { return (WrappedComponent) => { class FetchOnLoad extends React.Component { constructor(props) { fn(this.context.store); } } render() { return ( <WrappedComponent {...this.props} /> ); } } return FetchOnLoad; };

But constructor is called both on server and client

Let s change it export default function fetch(fn) { return (WrappedComponent) => { class FetchOnLoad extends React.Component { componentdidmount(props) { fn(this.context.store); } } render() { return ( <WrappedComponent {...this.props} /> ); } } FetchOnLoad.fetch = fn; return FetchOnLoad; };

On the server components.filter(component => Boolean(component && component.fetch)).map(component => component.fetch(store))

The problem to have information about these components

The solution is simple: let s avoid dealing with components at all

Universal fetch export default function fetch(fn) { const fetch = props => store => fn(store, props) return (WrappedComponent) => { class FetchOnLoad extends React.Component { constructor(props, context) { super(props); if (context.fetches) { context.fetches.push(fetch(props)); } } componentdidmount() { if (!window. INITIAL_STATE ) { fn(this.context.store, this.props); } } render() { return ( <WrappedComponent {...this.props} /> ); } } return FetchOnLoad...

On the server function renderapp(store, req, fetches) { return ReactDOMServer.renderToString( <Provider store={store}> <FetchProvider fetches={fetches}> <App /> </FetchProvider> </Provider>, ); }... // First render to collect all fetches const fetches = []; renderapp(store, req, fetches); const promises = fetches.map(fetch => fetch(store)); await Promise.all(promises);

FetchProvider export default class FetchProvider extends React.Component { getchildcontext() { return { fetches: this.props.fetches }; } } render() { return this.props.children; } FetchProvider.propTypes = { children: PropTypes.node.isRequired, fetches: PropTypes.array }; FetchProvider.childContextTypes = { fetches: PropTypes.array };

Demo

Conclusions We ve organized Code-Splitting + Server Side Rendering for big React application Plus added Universal Data Fetching

Links Main Project Link (https://github.com/northerneyes/react-stack-playground/tree/fetching) Webpack hot server middleware ( https://github.com/60frames/webpack-hot-server-middleware) Interesting github account (https://github.com/faceyspacey)

Other Links Usability Engineering, Jakob Nielsen, 1993 (https://www.nngroup.com/books/usability-engineering/) Page Insights (https://developers.google.com/speed/pagespeed/insights/) HTTP/2 (https://en.wikipedia.org/wiki/http/2) Webpack 2 documentation (https://webpack.js.org/) React Loadable (https://github.com/thejameskyle/react-loadable) Medium article (https://medium.com/@thejameskyle/react-loadable-2674c59de178) Alternatives (https://github.com/ctrlplusb/react-async-component) React router v4 (https://reacttraining.com/react-router/web/guides/code-splitting/code-splitting-server-rendering) Webpack 2 code-splitting (https://webpack.js.org/guides/code-splitting-async/)

Thanks! George Bukhanov github.com/northerneyes medium.com/@northerneyes twitter.com/nordfinn React Loadable: Code Splitting with Server Side Rendering