What is SSR, which problems does it solve, why do it in PHP, what options do we have for it, libraries that are available and tips and tricks. Practical code examples for Symfony and React.js, but the fundamental points can be taken away to use in other stacks like Vue and Laravel.
2. Nacho Martín
I write code at Limenius.
We build tailor-made projects,
and provide consultancy and formation.
We are very happy with React, and have been
dealing with how to integrate with PHP for
some time now & publishing libraries about
it.
3. What is the problem that
Server Side Rendering
adresses?
20. Nacho Martín
nacho@limenius.com
@nacmartin
DOM Manipulation
This happens in the Browser
Element
<body>
Element
<div id=“grid”>
Element
<h1>
Text
“Hi there”
…
Element
<div>
Element
<div>
API
$.get( “api/page2.json“,
function(data) {
$(“#grid”).html(renderPage(data));
}
);
22. Nacho Martín
nacho@limenius.com
@nacmartin
DOM Manipulation
This happens in the Browser
Element
<body>
Element
<div id=“grid”>
Element
<h1>
Text
“Hi there”
…
Element
<div>
Element
<div>
API
$.get( “api/page2.json“,
function(data) {
$(“#grid”).html(renderPage(data));
}
);
28. Nacho Martín
nacho@limenius.com
@nacmartin
Slow page loads in mobile users
https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/
• Average load time over 3G: 19 seconds.
• 53% of sites that take longer than 3s are abandoned.
• Going from 19s to 5s means:
• 25% more impressions of ads.
• 70% longer sessions.
• 35% lower bounce race.
• 2x ad revenue.
40. Nacho Martín
nacho@limenius.com
@nacmartin
Options
2: Find in the DOM where to
insert elements, what to move,
what to remove…
1: Re-render everything. Simple
EfficientComplex
Not efficient
React allows us to do 1, although it does 2 behind the scenes
50. Nacho Martín
nacho@limenius.com
@nacmartin
render() and JSX
render() {
return (
<div className="App">
<button onClick={this.tick.bind(this)}>Clícame!</button>
<span>Clicks: {this.state.count}</span>
</div>
);
It is not HTML, it is JSX.
React transforms it internally to HTML elements.
Good practice: make render() as clean as possible, only a return.
52. Nacho Martín
nacho@limenius.com
@nacmartin
render() and JSX
render() {
return (
<div className="App">
<button onClick={this.tick.bind(this)}>Click me!</button>
<span>Clicks: {this.state.count}</span>
</div>
);
}
Here we don’t modify the state
53. Nacho Martín
nacho@limenius.com
@nacmartin
render() and JSX
render() {
return (
<div className="App">
<button onClick={this.tick.bind(this)}>Click me!</button>
<span>Clicks: {this.state.count}</span>
</div>
);
}
Here we don’t make Ajax calls
54. Nacho Martín
nacho@limenius.com
@nacmartin
render() and JSX
render() {
return (
<div className="App">
<button onClick={this.tick.bind(this)}>Click me!</button>
<span>Clicks: {this.state.count}</span>
</div>
);
}
Here we don’t calculate decimals of PI and send an e-mail
with the result
72. Nacho Martín
nacho@limenius.com
@nacmartin
SSR in React. 2) insert in our template
<html>
…
<body>
<div id=“root”>
<div data-reactroot="">
This is some <span>server-generated</span> <span>HTML.</span>
</div>
</div>
…
75. Nacho Martín
nacho@limenius.com
@nacmartin
React, Vue, but does my library support this?
If what is rendered depends on the state then
we are probably good.
If your JS depends on having the DOM loaded
and manipulate it, then we are not good.
81. Nacho Martín
nacho@limenius.com
@nacmartin
Why?
SSR in JavaScript (node.js) is more natural.
But it may not be the right choice for the project.
Maybe the team has expertise in PHP.
Maybe the project already exists.
Maybe we want to combine it with sections
rendered from PHP.
The Real World is not as simple as tutorials.
85. Nacho Martín
nacho@limenius.com
@nacmartin
JS Code to execute
Server side JS App
+
Component and state that we want to render
A few bytes,
Changes between
requests
As big as your app.
Doesn’t change
between requests
92. Nacho Martín
nacho@limenius.com
@nacmartin
Make a call to node.js using Symfony Process component
* Easy to setup.
* Slow.
Library: https://github.com/nacmartin/phpexecjs
Option 1: Call a node.js subprocess
102. Nacho Martín
nacho@limenius.com
@nacmartin
We have “stupid” node.js server used only to render components.
It has <100 LoC, and it doesn’t know anything about our logic.
* Fast.
There is an example a dummy JS server for this purpose at
https://github.com/Limenius/symfony-react-sandbox
Option 3: External node.js server
121. Nacho Martín
nacho@limenius.com
@nacmartin
Then in Twig
{% set recipes = react_component_array('RecipesApp', {'props': props}) %}
{% block title %}
{{ recipes.title is defined ? recipes.title | raw : '' }}
{% endblock title %}
{% block body %}
{{ recipes.componentHtml | raw }}{{ redux_store('recipesStore', initialState) }}
{% endblock body %}
123. Nacho Martín
nacho@limenius.com
@nacmartin
Better to try it soon
Certain JS code doesn’t make sense in SSR:
• Timers: SetTimeout, setInterval.
• Access to window, or document objects.
• Access to the DOM.
• First render that depends on weird things like API calls (this is a smell).
Don’t wait until the last moment to check SSR if it is in the roadmap
124. Summary:
What is SSR and what is it for
Ways to do it in PHP (pros & cons)
Some libraries
Tips & practical problems