About me
Presentation Infrastructure Team
(also Hackdays, [in]cubator, Engineering Blog, Open Source)
Outline
1. A little LinkedIn history
2. A new direction: client side rendering
3. Picking a templating technology
4. Take dust for a spin
5. Challenges: SEO, i18n, logic
6. The Future
Outline
1. A little LinkedIn history
2. A new direction: client side rendering
3. Picking a templating technology
4. Take dust for a spin
5. Challenges: SEO, i18n, logic
6. The Future
LinkedIn in 2010
New web frameworks to boost productivity:
Grails/GSPs, JRuby/ERBs, plus others
Fragmentation
● Each tech stack used a different templating
technology (JSP, GSP, ERB, etc)
● No easy way to share UI code for common
components (e.g. profile, the feed)
● The "global" nav had to be rewritten in
multiple languages/technologies. Updating it
was very time consuming.
Outline
1. A little LinkedIn history
2. A new direction: client side rendering
3. Picking a templating technology
4. Take dust for a spin
5. Challenges: SEO, i18n, logic
6. The Future
Client side rendering (simplified)
Server sends JSON. The template is fetched from the CDN and
rendered in browser.
Client side rendering (full)
Server sends JSON embedded in an HTML skeleton. The skeleton
has JavaScript code that fetches and renders the template.
Client side MVC
Client side MVC makes client side rendering even more important.
Client side rendering (with MVC)
Once a page has loaded, the client side MVC takes over, fetching
JSON from the server and rendering it with client side templates
Client side rendering benefits
● DRY: works with any server side stack plus
client side
● Performance: bandwidth, latency, caching
● Productivity: fast iteration, mock JSON
● Rich apps: client side MVC
Outline
1. A little LinkedIn history
2. A new direction: client side rendering
3. Picking a templating technology
4. Take dust for a spin
5. Challenges: SEO, i18n, logic
6. The Future
Decisions, decisions
We evaluated 26 different options. They tended to fall into one of
two groups: Embedded JavaScript and Logic Less.
Embedded JavaScript Templates
<ul>
<% for(var i = 0; i < supplies.length; i ++) { %>
<li><%= supplies[i] %> </li>
<% } %>
</ul>
Normal JavaScript code directly in the template.
The rules
● Produce this HTML output
● Use this profile JSON as input
● The same template should render on the server-side
and client-side
● Properly handle profile data display rules
● Format numbers and dates correctly
The criteria
● DRY
● i18n
● Hot reload
● Performance
● Ramp-up time
● Ramped-up productivity
● Server/client support
● Community
● Library agnostic
● Testable
● Debuggable
● Editor support
● Maturity
● Documentation
● Code documentation
Google Closure Templates
Pros
● Templates are compiled into JavaScript for client-side and Java for server-
side.
● Good built-in functionality: loops, conditionals, partials, i18n.
● Documentation is enforced by the template.
Cons
● Very little usage outside of Google. No plans to push new versions or
accept new contributions.
● Some functionality is missing, such as being able to loop over maps.
● Not DRY: adding new functionality requires implementing plugins in both
Java and JavaScript.
Mustache
Pros
● Very popular choice with a large, active community.
● Server side support in many languages, including Java.
● Logic-less templates do a great job of forcing you to separate presentation
from logic.
● Clean syntax leads to templates that are easy to build, read, and maintain.
Cons
● A little too logic-less: basic tasks (e.g. label alternate rows with different
CSS classes) are difficult.
● View logic is often pushed back to the server or implemented as a
"lambda" (callable function).
● For lambdas to work on client and server, you must write them in
JavaScript.
● Slow, interpreted templates
Handlebars
Pros
● Logic-less templates do a great job of forcing you to separate presentation
from logic.
● Clean syntax leads to templates that are easy to build, read, and maintain.
● Compiled rather than interpreted templates.
● Better support for paths than mustache (ie, reaching deep into a context
object).
● Better support for global helpers than mustache.
Cons
● Requires server-side JavaScript to render on the server.
Dust.js
Pros
● Logic-less templates do a great job of forcing you to separate presentation
from logic.
● Clean syntax leads to templates that are easy to build, read, and maintain.
● Compiled rather than interpreted templates.
● Better support for paths than mustache (ie, reaching deep into a context
object).
● Better support for global helpers than mustache.
● Inline parameters.
● Blocks & inline partials.
● Overriding contexts.
● Support for asynchronous rendering and streaming.
● Composable templates.
Cons
● Requires server-side JavaScript to render on the server.
● Maintainer of github repo is not responsive.
Takeaways
● Based on how we weighed our criteria, Dust
fit our needs the best
● Use real use cases and identify the most
important criteria to you
● For non-trivial views, no templating option
works on client and server, unless your
server executes JavaScript (v8, Rhino)
Outline
1. A little LinkedIn history
2. A new direction: client side rendering
3. Picking a templating technology
4. Take dust for a spin
5. Challenges: SEO, i18n, logic
6. The Future
The LinkedIn Fork
● The original maintainer abandoned dust
● The LinkedIn fork is now the most active
● We've added bug fixes, perf improvements,
and helpers
Try it out
● Homepage:
http://linkedin.github.com/dustjs/
● Try it in the browser: http://linkedin.github.
com/dustjs/test/test.html
● Source code: https://github.
com/linkedin/dustjs
Outline
1. A little LinkedIn history
2. A new direction: client side rendering
3. Picking a templating technology
4. Take dust for a spin
5. Challenges: SEO, i18n, logic
6. The Future
Helpers to the rescue: @eq, @ne
{@eq key="foo" value="foo"}The key and value are equal!{/ eq}
{@ne key="foo" value="bar"}The key and value are not equal!{/ ne}
Helpers to the rescue: @gt, @lt
{@gt key="22" value="3"}22 is greater than 3{/ gt}
{@lt key="0" value="500"}0 is less than 500{/ lt}
Helpers to the rescue: @select
{@select key=age}
{@eq value="1"}Baby{/eq}
{@lt value="10"}Child{/lt}
{@lt value="18"}Teen{/lt}
{@default}Adult{/default}
{/select}
Helpers to the rescue: @size, @math
You have {@ size key=list/} new messages
{@math key="16" method="add" operand="4"/}
Full library of helpers is available at:
https://github.com/linkedin/dustjs-helpers
How do we handled clients without
JavaScript? What about SEO?
SSR: Server Side Rendering
● Google V8 engine
● A plugin for Apache Traffic Server
● Executes arbitrary JavaScript server side,
including rendering dust templates
● Often nicknamed Unified Server Side
Rendering... aka, USSR
Client side rendering (full, SSR)
The HTML Skeleton is written in dust. SSR renders it as HTML.
SSR uses
● Render dust skeleton into HTML skeleton
● Render everything server side for:
○ Crawlers/bots/search engines
○ Clients without JavaScript
○ Slow clients (IE < 8)
● Logic less templates help ensure that
everything renders correctly server-side. No
DOM dependencies!
Server side templates
<p>
<a href="${url.link( 'home-page' }">$!{i18n('hello-world' )}</a>
</p>
In JSPs, Java libraries did i18n, text formatting, URL generation
Sending an entire i18n dictionary,
URL dictionary, and all formatting
code to the browser is expensive
Option #1: everything server side
Java controller
json.put("name", "Jim");
json.put("home-page-link" , Url.link("home-page" ));
json.put("hello-world-text" , I18n.get("hello-world" ));
render("profile-page" , json);
profile-page dust template
<p>
<a href="{home-page-link} ">{hello-world-text} </a>
</p>
All i18n, text formatting, and URL generation is done server side
and added to the JSON payload
Option #1: everything server side
Pros
● Simple, easy to understand
● Clean templates
Cons
● Controller code cluttered with view logic
Option #2: dynamic pre-processing
Original profile-page dust template
<p>
<a href="{@pre.link key="home-page"}
">{@pre.i18n key="hello-world"}
</a>
</p>
Pre-processed profile-page dust template
<p>
<a href="{link-123}">{i18n-456}</a>
</p>
Step 1: the @pre helper tags get replaced at build time with
references to unique keys in the JSON
Option #2: dynamic pre-processing
Java controller
json.put("name", "Jim");
render("profile-page" , json);
Pre-processed JSON
{
"name": "Jim",
"link-123" : "http://www.linkedin.com" ,
"i18n-456" : "Hello World"
}
Step 2: whenever profile-page is rendered, automatically
"enhance" the JSON with the requested i18n and URL values
Option #2: dynamic pre-processing
Pros
● All view logic is in the templates
● Clean server side code
Cons
● Complicated, hard to debug
● Tight coupling: need special server and build
logic to use templates
● Performance: increased JSON payload
and/or more server processing time
Option #3: static pre-processing
Original profile-page dust template
<p>
<a href="{home-page-link}">{@i18n}Hello World{/i18n}</a>
</p>
Pre-processed profile-page dust template (one per language)
<p>
<a href="{home-page-link}">Hello World</a>
</p>
<p>
<a href="{home-page-link}">Bonjour monde</a>
</p>
Generate one template per language with translated text already
filled in. Link generation and formatting still happen server-side.
Option #3: static pre-processing
Pros
● Hybrid approach: i18n is in the templates,
only formatting/link generation is in controller
● Simpler, easier to debug than dynamic pre-
processing
Cons
● Custom build process
● Increased template payload, but i18n strings
now cached with template
Outline
1. A little LinkedIn history
2. A new direction: client side rendering
3. Picking a templating technology
4. Take dust for a spin
5. Challenges: SEO, i18n, logic
6. The Future
LinkedIn in 2013
We now many services using client side rendering and
many using server-side rendering
Fizzy
Fizzy is an ATS plugin that reads the HTML (skeleton or
full) returned by webapps
Fizzy
<html>
<body>
<h1>Composable UI </h1>
<script type="fs/embed" fs-uri="/news-feed/top" ></script>
<script type="fs/embed" fs-uri="/pymk"></script>
<script type="fs/embed" fs-uri="/ad"></script>
</body>
</html>
If Fizzy finds an fs/embed in the HTML, it calls the URI and injects
the response into the page.
Fizzy
HTML skeleton
Embed
Embed
Embed
A page now consists of a skeleton with a bunch of Fizzy-
processed embeds.
Typical page
HTML Skeleton
Dust
template
Dust template
Dust
The fold template
Dust template Dust
template
Dust template
On initial page load, the user doesn't see anything below the fold
Typical page
HTML Skeleton
Dust
template
Dust template
Dust
The fold template
Dust template Dust
template
No need
to render Dust template
No need to fetch
data or render
Deferred rendering
● Dramatically improve performance by not
rendering anything below the fold
● Improve it even further by not fetching the
data for things far out of view
● The challenge: the fold is at different
positions on different devices
Outline
1. A little LinkedIn history
2. A new direction: client side rendering
3. Picking a templating technology
4. Take dust for a spin
5. Challenges: SEO, i18n, logic
6. The Future
Final thoughts
● Dust.js has improved developer productivity and code
sharing at LinkedIn
● Client side templating offers powerful new capabilities
and benefits
● It also introduces tough new challenges
● It's an evolving technology; now is a good time to get
involved