At Pinterest, we've begun experimenting in production with Web Components. This talk will discuss some challenges of implementing Web Components in a large scale production environment such as SEO concerns, reasonable fallbacks for browsers not supported by Platform.js, migrating a large code base component-by-component to mitigate risk, and optimizing page load and scroll performance.
8. Background
Web architecture
Web server
Routing
Templates
Render a component tree
Behavior (event handlers)
Duplication
9. Background
Existing component system
• Backbone View
• Backbone Model
• templates render to an HTML string, then innerHTML to
load
• re-rendering a subtree throws away the old subtree
entirely
12. Background
Web Components score card
• Migrate gradually
• Compatible with existing tooling
• Content Security Policy
• Page load performance (too much)
• Don’t hurt SEO
• Encapsulation of DOM and styles
• Don’t cut off too many browser versions
20. Don’t break Content Security Policy
Polyfill problems
• The HTML Imports polyfill loads imports using
XMLHttpRequest then evals script
21. Requirements
Content Security Policy
• If you keep your styles and
scripts external, there’s no
action needed.
• If you write inline styles or
inline scripts, use the “csp”
flag and Vulcanize will
extract them to separate
files.
grunt.initConfig({
vulcanize: {
options: {
csp: true,
...
},
files: {
'out.html': 'comps/**.html'
},
},
});
23. Server-side Rendering
• No story at all for Web Components/Polymer
• If we can get away with it, we’d rather eliminate the Python
code path for templates/rendering
• What is the impact on
• Page load times?
• SEO?
24. Page Load Performance
Nice to have
• Not critical, but don’t want to regress more than 10-20%.
• The median user has < 2 page refreshes per visit. Almost
every interaction is a pushState.
• Indirectly affects SEO (speed is a factor in scoring).
25. Page Load Performance
Experiment
• Control: Render the initial content sever-side in Python and
send it as HTML in the page load
• Treatment: Serve meta tags and correct HTTP response
codes, but render all of the visible content in JS.
• Measure using Web Page Test’s SpeedIndex - a measure of
how early the final pixels are painted. Lower is better.
• An explanation of SpeedIndex
28. SEO
Important to not regress
• Web doesn’t have the most active users of all the Pinterest
client apps.
• Web is the largest source of acquisition.
29. SEO
Organic search traffic by source
In practice, we are targeting Google crawler.
30. SEO
Does Google’s crawler understand JS?
Historically: “No”
May 23, 2014:
“we decided to try to (better)
understand pages by executing
JavaScript”
-Google
31. SEO
A/B test JS-rendered page
• 10% of “Board” pages will render all of their components
client-side
• Takes Google roughly 1 week to re-index all content and for
us to see the true impact
32. SEO
5% decline in traffic vs. control group after only 1.5 days
33. SEO
“Fetch as Google”
• A tool in Google Webmaster Tools that
shows what the crawler sees.
Rendering pages with Fetch as Google
post
34. • Crawler is seeing some
client-rendered
components. (yay!)
• Content area of the
page was blank. (boo)
• An XHRs was needed
to render the content,
but the crawler
blocked it. Eliminate
the need for the XHR.
37. DOM Encapsulation
Shadow DOM
It’s a heroic (crazy?) effort to make this
work as a polyfill.
Overrides
• 20 methods on HTMLElement
• 44 methods on Document
• 69 element contructors
38. DOM Encapsulation
Shadow DOM, continued
Quirks
• document, window, document.body, document.head
can’t be wrapped by the polyfill, and you need to manually
wrap:
• wrap(document.body)
• Console shortcuts to grab elements return the unwrapped
element and need to be wrapped.
• wrap($0)
42. Style Encapsulation
Shadow CSS - limitations
“For browsers that lack native support, Polymer’s polyfills
attempt to shim some of the scoping behavior.”
-Polyfill Details
44. Style Encapsulation
Shadow CSS - limitations galore
Can’t polyfill lower-bound encapsulation
• Platform.ShadowCSS.strictStyling = true;
• Requires that you add custom element’s name as an attribute
on all DOM nodes in the shadowRoot e.g. <span x-foo>
• Nobody is going to do that without a build step, so why bother
polyfilling this at all?
45.
46. Unless you like testing in different browsers
• Force the Shadow DOM polyfill to be enabled.
52. Browser Compatibility
Anecdotes
• Chrome 37 crashes frequently
with dev tools open making
tweaks to the Polymer tutorial
• iOS8 was broken well after the
GM shipped and didn’t work until
just before public launch
53. Browser Compat
Anecdotes - IE10
• the renderer process locks up on
an unpatched IE10 (e.g. modern.ie
image that has updates turned off)
61. Next Steps
• SEO
• eliminate the XHR, reset the experiment
• Browser compatibility
• try to measure impact on IE10
• Pieces of platform.js that work on more browsers (Custom
Elements?)
• Finish evaluating other framework options