Date post: | 02-Jul-2015 |
Category: |
Technology |
Upload: | chris-danford |
View: | 319 times |
Download: | 0 times |
Chris Danford, @chrisdanfordPinterest Web Team
Web Components at Scale2014-10-20
Pinterest’s evaluation of Web ComponentsTopic Covered
• Migrating from our existing component framework• SEO impact• Page load perf• Polyfill gotchas• Browser compatibility
Background Learnings Conclusion TODO
2 years since major design decisions madeBackground
Pinterest has grownBackground
Then 7 engineers touching web
Now 70 engineers touching web
ArchitectureBackground
API
Android
Datalayer
iOSWeb
Graph ServiceSearch
Client Apps
Back-endServices
...
Web architectureBackground
Web server
Routing
Templates
Render a component tree
Behavior (event handlers)
Duplication
Existing component systemBackground
• Backbone View• Backbone Model• templates render to an HTML string, then innerHTML to
load• re-rendering a subtree throws away the old subtree
entirely
Style (.scss)
Structure (.html)
Behavior (.js)
from a template
from JS
Web Components score cardBackground
• 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
Background Learnings Conclusion TODO
Custom Elements lifecycle functionsMigrate Gradually
Pinterest onCreated
onAddedToDomonContentReady
onRemovedFromDom
Custom Elements createdCallbackattachedCallback
—detachedCallback
Polymer created
attacheddomReadydetached
Each component renders itself in attachedCallbackQuick prototype
Migrate Gradually
Can work with existing toolingPreserve Existing Tools
• SASS• ESLint• Closure Compiler• Syntax-highlighting editors
External scripts and stylesheets are no problemPreserve Existing Tools
• Polymer docs: Separating scripts from markup
Works with Existing Tooling
Polyfill problemsDon’t break Content Security Policy
• The HTML Imports polyfill loads imports using XMLHttpRequest then evals script
Content Security PolicyRequirements
• 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' }, }, });
Content Security Policy
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?
Nice to havePage Load Performance
• 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).
ExperimentPage Load Performance
• 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
Page Load Performance
Server-rendered JS-rendered Difference
First View 5073 5236 3%
Repeat View 2571 3114 20%
SpeedIndex, San Jose, DSL, Chrome
Page Load Performance
A pleasant surprise!
Important to not regressSEO
• Web doesn’t have the most active users of all the Pinterest client apps.
• Web is the largest source of acquisition.
Organic search traffic by sourceSEO
In practice, we are targeting Google crawler.
Does Google’s crawler understand JS?SEO
Historically: “No”
May 23, 2014:“we decided to try to (better) understand pages by executing JavaScript”
A/B test JS-rendered pageSEO
• 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
SEO
5% decline in traffic vs. control group after only 1.5 days
“Fetch as Google”SEO
• A tool in Google Webmaster Tools that shows what the crawler sees.
Rendering pages with Fetch as Google post
• 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.
Next experimentSEO
• Inline the data into the page to eliminate the XHR.
SEO
But I’m optimistic!
Shadow DOMDOM Encapsulation
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
Shadow DOM, continuedDOM Encapsulation
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)
Shadow CSSStyle Encapsulation
A style shimmer: re-writes CSS text with a bunch of regexes
Shadow CSS - what worksStyle Encapsulation
• Replace :host with element selector• Add upper-bound encapsulation by prepending element
selector
Easy with a CSS preprocessor tooStyle Encapsulation
Shadow CSS - limitationsStyle Encapsulation
“For browsers that lack native support, Polymer’s polyfills attempt to shim some of the scoping behavior.”
-Polyfill Details
Chrome 38 (native) Firefox 32 (polyfill)
Shadow CSS - limitations galoreStyle Encapsulation
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?
Unless you like testing in different browsers
• Force the Shadow DOM polyfill to be enabled.
Shadow DOMShadow CSS
Polymer-stated supportBrowser Compatibility
IE < 10 is hopelessSafari < 6 is hopeless
https://www.polymer-project.org/resources/compatibility.html
Pinterest browsers by visitorBrowser Compatibility
5.05%+ of visitors incompatible
Pinterest browsers by visitorBrowser Compatibility
5.05%+ of visitors incompatible9.25%+
AnecdotesBrowser Compatibility
• Android Browser 4.1 and 4.3 not working with any of the demos
AnecdotesBrowser Compatibility
• 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
Anecdotes - IE10Browser Compat
• the renderer process locks up on an unpatched IE10 (e.g. modern.ie image that has updates turned off)
Anecdotes - IE10Browser Compat
10.0.10 10.0.20
Anecdotes - IE10Browser Compat
• Can’t tell how many users this might impact because build # isn’t in the UA string.
Browser Compatibility
Background Learnings Conclusion TODO
Conclusion
Migrate GraduallyWorks with Existing Tooling
Content Security PolicyPage Load Performance
SEOShadow DOMShadow CSS
Browser Compatibility
Polymer architecture
Polymer.js
• TemplateBinding• syntactic sugar
(polymer-element tag, on-*event* attribute binding)
• tooling (Vulcanize, Polymer Designer)
core-elements
paper-elements
Platform.js
“Prollyfills”• ShadowDOM• HTMLImports• Custom Elements• MutationObserver• Object.observe
• menus• drawers• panels• animation
framework
Background Learnings Conclusion TODO
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