Server-Side Rendering Isn't Enough
Matthew Phillips
@matthewcp
Terms
- Shared codebase
- Isomorphic
- Universal
Why bother
Perceived performance: no one likes staring at a spinner.
This sucks
SEO: if you care about that sort of thing, it helps. Not every bot is Googlebot.
BLING BLING: Amazon reports that conversion increased by 1% for every 100ms improvement.
The state of Server Rendering
Everything should be server rendered
Requirements
- Rendering speed
- Only includes the assets needed (CSS and JavaScript)
- Prevents unnecessary requests in the client
Performance
- Shared router
- Asynchronous rendering
- Fast development experience with hot module swapping
Maintainability
Rendering Performance
Headless Browser
PhantomJS
- Consumed a lot of memory
- Needed pooling
- Very fast
Virtual DOMS
- Run the same code on the client and server
- Run within a single Node context
- Rendering is usually synchronous
can-ssr's vdom
Looks like a real DOM, only the basics
Demo compatibility
Minimizing request size
/cart
Title
Traditional method
- Initially unstyled
- Main, site-wide style is loaded
- Page specific style is loaded progressively.
CSS loaded in JavaScript
/cart
Title
with server template
- Initially partially styled; main CSS is included, most of the page-specific CSS.
- Rest of page-specific styles are added.
adding css manually
/cart
Title
With Donejs
- All styles needed for the page are included directly in the head.
- And only the styles needed for the page.
can-ssr does it for you
import Framework from 'fancy-framework';
import './styles.scss';
...
Component-based architecture
Minimizing the number of requests
Prevent redundant requests
<script>
INLINE_CACHE = {"users": [{ ... } ] };
</script>
- Embed responses into the rendered page.
- Can be reused on the client to do initial rendering.
shared code-base
HOw much code is shared?
Minimizing differences for easier maintainence
- Same templating engine is used on server and client.
- A "main" that runs in both contexts.
- A shared router, not adding new routes in separate places
can-ssr Example
var ssr = require("can-ssr/middleware");
var app = require("express")();
app.use(ssr());
Middleware
var ssr = require("can-ssr");
var render = ssr();
render("/cart").then(function(result){
console.log(result.html);
});
Core API
export function createState(request){
// url could be: /, /profile, /messages, etc.
const page = request.url.split("/").pop() || "home";
return {
page: page
};
}
export function render(document, state){
$("<title>").text("jQuery App").appendTo(document.head);
let body = $(document.body);
body.append(template());
// Show the tab selected in the state
body.find(`[aria-controls=${state.page}]`).tab("show");
}
asynchronous rendering
Synchronous Rendering
- Forces all data to be present before rendering.
- Cannot use component-based architecture.
- Pushes application logic into another layer.
- Makes writing reusable components harder.
// server.js
import render from "framework-dom";
app.get("/cart", function(req, res){
fetchCart().then(function(data){
res.send(
render(data)
);
});
});
// cart.js
import Component from "fancy-framework";
class Cart extends Component {
render() {
let data = this.props.data;
return <div> ... </div>
}
}
Demo asynchronous react
INSTANT DEV WORKFLOW
hot module replacement
demo donejs live-reload
Take aways
- Only include the JavaScript and CSS needed for the request.
- Include any API responses in the response HTML. Reuse these in the client for initial rendering.
- Use a router that works on both the client and server.
- Component-based architecture is good, use it, with asynchronous rendering.
The End
BY Matthew Phillips
Server-Side Rendering Isn't Enough
By Matthew Phillips
Server-Side Rendering Isn't Enough
- 392