SlideShare a Scribd company logo
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
React loadable
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
Loadable
import Loadable from 'react-loadable';
function MyLoadingComponent() {
return <div>Loading...</div>;
}
const LoadableAnotherComponent = Loadable({
loader: () => import('./another-component'),
LoadingComponent: MyLoadingComponent
});
class MyComponent extends React.Component {
render() {
return <LoadableAnotherComponent/>;
}
}
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
Loadable
import Loadable from 'react-loadable';
function MyLoadingComponent() {
return <div>Loading...</div>;
}
const LoadableAnotherComponent = Loadable({
loader: () => import('./another-component'),
LoadingComponent: MyLoadingComponent
});
class MyComponent extends React.Component {
render() {
return <LoadableAnotherComponent/>;
}
}
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/)
George Bukhanov
● github.com/northerneyes
● medium.com/@northerneyes
● twitter.com/nordfinn
Thanks!
React Loadable:
Code Splitting with Server Side
Rendering

More Related Content

PDF
Angular performance slides
PDF
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
PPTX
Dsc Charusat Learning React Part 1
PDF
Angular - Improve Runtime performance 2019
PDF
Angular server side rendering - Strategies & Technics
PDF
Java Intro: Unit1. Hello World
PDF
Intro to JavaScript
Angular performance slides
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
Dsc Charusat Learning React Part 1
Angular - Improve Runtime performance 2019
Angular server side rendering - Strategies & Technics
Java Intro: Unit1. Hello World
Intro to JavaScript

What's hot (20)

PDF
AngularJS Unit Test
PPT
2007 Zend Con Mvc
PPTX
Testing Ansible
PDF
Seven Versions of One Web Application
PDF
Server side rendering with React and Symfony
PDF
Corso su ReactJS
PDF
Karma - JS Test Runner
PDF
Exploring Angular 2 - Episode 1
PPT
PDF
Introduction to Performance APIs
PDF
Introduction of React.js
PDF
Node.js and Selenium Webdriver, a journey from the Java side
PDF
Speed up your Web applications with HTML5 WebSockets
PPTX
AngularJS Unit Testing
PDF
Ruby on rails integration testing with minitest and capybara
PDF
AngularJS with RequireJS
PDF
Workshop 13: AngularJS Parte II
PDF
How to create an Angular builder
PPTX
Web Performance & Latest in React
PDF
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
AngularJS Unit Test
2007 Zend Con Mvc
Testing Ansible
Seven Versions of One Web Application
Server side rendering with React and Symfony
Corso su ReactJS
Karma - JS Test Runner
Exploring Angular 2 - Episode 1
Introduction to Performance APIs
Introduction of React.js
Node.js and Selenium Webdriver, a journey from the Java side
Speed up your Web applications with HTML5 WebSockets
AngularJS Unit Testing
Ruby on rails integration testing with minitest and capybara
AngularJS with RequireJS
Workshop 13: AngularJS Parte II
How to create an Angular builder
Web Performance & Latest in React
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 2
Ad

Similar to React loadable (20)

PDF
Workshop 27: Isomorphic web apps with ReactJS
PDF
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
PDF
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
PDF
Rest web service_with_spring_hateoas
PPTX
Full Stack_Reac web Development and Application
PDF
reactjs-quiz..docs.pdf
PDF
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
PPTX
Reactive application using meteor
PPTX
NEXTjs.pptxfggfgfdgfgfdgfdgfdgfdgfdgfdgfg
PPTX
How to implement multiple layouts using React router V4.pptx
PPTX
React JS CONCEPT AND DETAILED EXPLANATION
PDF
Full Stack React Workshop [CSSC x GDSC]
PDF
Production Experience: Some Insights from Using Vercel and Next.js for Over 3...
PDF
Reactive Application Using METEOR
KEY
Architecting single-page front-end apps
PDF
Mastering React Server Components and Server Actions in React 19
PPTX
React js programming concept
PPTX
React - Start learning today
PPTX
How to create components in react js
PPTX
What is code splitting in react
Workshop 27: Isomorphic web apps with ReactJS
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Rest web service_with_spring_hateoas
Full Stack_Reac web Development and Application
reactjs-quiz..docs.pdf
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
Reactive application using meteor
NEXTjs.pptxfggfgfdgfgfdgfdgfdgfdgfdgfdgfg
How to implement multiple layouts using React router V4.pptx
React JS CONCEPT AND DETAILED EXPLANATION
Full Stack React Workshop [CSSC x GDSC]
Production Experience: Some Insights from Using Vercel and Next.js for Over 3...
Reactive Application Using METEOR
Architecting single-page front-end apps
Mastering React Server Components and Server Actions in React 19
React js programming concept
React - Start learning today
How to create components in react js
What is code splitting in react
Ad

Recently uploaded (20)

PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PDF
top salesforce developer skills in 2025.pdf
PPTX
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
System and Network Administration Chapter 2
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
Understanding Forklifts - TECH EHS Solution
PDF
Digital Systems & Binary Numbers (comprehensive )
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
System and Network Administraation Chapter 3
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
top salesforce developer skills in 2025.pdf
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
2025 Textile ERP Trends: SAP, Odoo & Oracle
System and Network Administration Chapter 2
Upgrade and Innovation Strategies for SAP ERP Customers
Operating system designcfffgfgggggggvggggggggg
How to Choose the Right IT Partner for Your Business in Malaysia
Wondershare Filmora 15 Crack With Activation Key [2025
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
Which alternative to Crystal Reports is best for small or large businesses.pdf
Design an Analysis of Algorithms I-SECS-1021-03
Understanding Forklifts - TECH EHS Solution
Digital Systems & Binary Numbers (comprehensive )
Internet Downloader Manager (IDM) Crack 6.42 Build 41
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
How to Migrate SBCGlobal Email to Yahoo Easily
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
System and Network Administraation Chapter 3

React loadable

  • 1. React Loadable: Code Splitting with Server Side Rendering
  • 2. About me ● Former Senior Frontend Developer at Oppex ● Tech Lead at Toughbyte Ltd ● React ● github.com/northerneyes ● medium.com/@northerneyes ● twitter.com/nordfinn
  • 3. Agenda ● Problem statement ● Code-Splitting ● Server Side Rendering ● Code-Splitting + Server Side Rendering ● Universal Data Fetching
  • 13. Demo
  • 15. We can do better
  • 19. More places to split apart our app: ● Modals ● Tabs ● Some hidden content ● And many more UI
  • 20. But you can use routing as well
  • 22. What is React Loadable?
  • 23. Small library created by @thejameskyle Loadable is Higher-Order Component (HoC)
  • 24. Example import AnotherComponent from './another-component'; class MyComponent extends React.Component { render() { return <AnotherComponent/>; } }
  • 26. 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/>; }; } }
  • 27. A bunch of manual work
  • 29. Loadable import Loadable from 'react-loadable'; function MyLoadingComponent() { return <div>Loading...</div>; } const LoadableAnotherComponent = Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent }); class MyComponent extends React.Component { render() { return <LoadableAnotherComponent/>; } }
  • 30. What about error handling?
  • 31. Error handling is simple function MyLoadingComponent({ error }) { if (error) { return <div>Error!</div>; } else { return <div>Loading...</div>; } }
  • 34. Demo
  • 35. Avoiding Flash Of Loading Component
  • 36. Do you remember the first slide?
  • 37. 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; } }
  • 38. Easy to change delay parameter Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent, delay: 300 });
  • 39. What else we can do?
  • 41. 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> ) } }
  • 43. What is Isomorphic Rendering?
  • 44. Rendering the web app on server and sending the complete HTML to the client.
  • 45. The client creates the HTML in memory(Virtual Dom), checks if there are changes and re-renders the page on client.
  • 47. Better UX as user gets the complete page on first hit to the server.
  • 48. Everybody like this picture :)
  • 49. Better SEO as the bots can easily index the pages
  • 51. Server Side Rendering with React is easy
  • 52. React Server Rendering import ReactDOMServer from 'react-dom/server'; ReactDOMServer.renderToString( <Provider store={store}> <StaticRouter location={req.url} context={{}}> <App /> </StaticRouter> </Provider>, );
  • 54. 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.
  • 55. How we can solve these problems?
  • 56. Let’s go back to React Loadable
  • 57. Loadable import Loadable from 'react-loadable'; function MyLoadingComponent() { return <div>Loading...</div>; } const LoadableAnotherComponent = Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent }); class MyComponent extends React.Component { render() { return <LoadableAnotherComponent/>; } }
  • 58. 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.
  • 59. 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.
  • 61. 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') });
  • 62. 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.
  • 63. 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.
  • 64. Yes, This is the most complicated
  • 65. We need 2 things
  • 66. webpack --json > output-webpack-stats.json
  • 67. 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; });
  • 68. 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); }); }); });
  • 69. 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> `) })
  • 70. Demo
  • 72. Fetching is simple class News extends React.Component { constructor(props) { super(props); props.getNews(); } render() { const { items } = this.props.news; return ( .... ); } }
  • 73. 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; }; }
  • 74. But constructor is called both on server and client
  • 75. 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; }; }
  • 76. On the server components.filter(component => Boolean(component && component.fetch)) .map(component => component.fetch(store))
  • 77. The problem to have information about these components
  • 78. The solution is simple: let’s avoid dealing with components at all
  • 79. 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 ...
  • 80. 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);
  • 81. 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 };
  • 82. Demo
  • 83. Conclusions ● We’ve organized Code-Splitting + Server Side Rendering for big React application ● Plus added Universal Data Fetching
  • 84. 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)
  • 85. 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/)
  • 86. George Bukhanov ● github.com/northerneyes ● medium.com/@northerneyes ● twitter.com/nordfinn Thanks! React Loadable: Code Splitting with Server Side Rendering