web developer @ Evozon Systems
Andrei Cacio
Google <3 SPAs
What are single page applications?
When did we start talking about them?
- till 2004 there was no such thing as a SPA
- "traditional" web applications
So what happened after 2004?
XMLHttpRequest
hapened
SEO before SPAs
- server-side template engines
- server-side render
- server-side routes
- mostly non dynamic content
Web applications
Crawlers and bots
- Google, Bing, Yahoo etc.
- would request the HTML
- ES5 was the new standard
- The number of JavaScript frameworks started to grow: ExtJS, Angular, Backbone etc.
- Template engines on the browser
- Client-side routing
- Nodejs was released (btw)
- etc.
2009
- client-side template engines
- client-side render
- client-side routes
- mostly dynamic content
Single page applications
SEO after SPAs
Crawlers and bots
- Google, Bing, Yahoo etc.
- would request the HTML
- client-side template engines
- client-side render
- client-side routes
- mostly dynamic content
Single page applications
* Google AJAX crawl scheme
2011
Google bot (and other crawlers)
vs
Browser
PhantomJS
a headless WebKit scriptable
# get.js
const system = require('system');
const webPage = require('webpage');
const page = webPage.create();
const address = system.args[1]
page.open(address, function (status) {
const content = page.content;
console.log('Content: ' + content);
phantom.exit();
});
$ phantomjs get.js http://google.com
Let's do some SEO with
PhantomJS
Demo
since the middle of 2014
... ish
Routes
#!
- The hash URLs
- Google AJAX crawl scheme
<meta name="fragment" content="!">
URL: /#!/page
Google bot: /_escaped_fragment=/page
It's deprecated!
... since late 2015
Routes
/
- Pretty URLs
- Google treats them as a normal routes
- HTML5 pushState
Route mirroring
var app = angular.module('spaapp', []);
app.config(['$routeProvider', '$locationProvider'
function($routeProvider, $locationProvider) {
$routeProvider.
when('/products', {
templateUrl: 'templates/products.html',
controller: 'ProductsController'
}).
when('/about', {
templateUrl: 'templates/about.html',
controller: 'AboutController'
}).
otherwise({
redirectTo: '/'
});
$locationProvider.html5Mode(true);
}]);
AngularJS routes
const express = require('express');
const app = express();
app.get('/', (reg, res) => {
res.render('index', { data: {} });
});
app.get('/about', (reg, res) => {
res.render('about', { data: {} });
});
app.get('/products', (reg, res) => {
res.render('products', { data: {} });
});
Express routes
this should apply regardless of what framework is used on both client or server
"Precomposing " a SPA
- Inline the content into a JSON object into your template
- Avoid unnecessary AJAX calls
- Lift the heavy weight off as much as possible
<!DOCTYPE html>
<html>
<head></head>
<body>
<script>
window.initialData = { ... };
</script>
<template id="my-template"> ... </template>
<script src="app.min.js"></script>
</body>
</html>
2015 - 2016
- can we do it better?
- could we avoid tools like PhantomJS
- and still have good SEO on other major crawlers?
We can go the isomorphic way
- libraries that run on the client and on the server
- leverage server-side rendering
How can we achieve this?
... among others
Write once, use everywhere
Super simple example
import React from 'react';
import ReactDOM from 'react-dom';
import Griddle from 'griddle-react';
import {fakeData} from '../fixtures/grid';
export const GriddleDefault = React.createClass({
render() {
return <Griddle results={fakeData} resultsPerPage={20}></Griddle>;
}
});
GridComponent.js
import React from 'react';
import ReactDOM from 'react-dom';
import {Grid} from './components/grid';
ReactDOM.render(<Grid />, document.getElementById('grid'));
index.js
doctype html
html
head
title= title
body
h1= title
div(id='grid')
Loading ...
script(src='/js/bundle.js')
index.jade
const express = require('express');
const React = require('react');
const renderToString = require('react-dom/server').renderToString;
const Grid = require('../client/app/components/grid');
const app = express();
app.get('/', (req, res) => {
res.render('index', {
react: renderToString(React.createElement(Grid))
});
});
server.js
Thank you!
All resources and slides can be found here:
Demo source code:
Questions?
Google <3 SPAs
By Andrei Cacio
Google <3 SPAs
- 2,790