Turbocharging Walmart.com: Speed without compromise Vasanth Krishnamoorthy vasanth_k vasanthk

Focus Areas Approaching Performance 7 Key Optimizations Guardrails for Performance

100 million+ customers per month Over 30% growth YoY

Performance as a Measure Of User Happiness

Typical Customer Journey Cart Checkout Product Home Page Page Search Tech Stack

Customer Journey 42% Improvement TTI - 95th %ile mobile web

PART 1 Approaching Performance

Where do you start?

“You can’t improve what you don’t measure”

Measure What Matters TTI – Time to interactive (custom) TTFB – Time to first byte TLOAD - Page is fully loaded (custom) TTFB TTI TLOAD

Define Your Scope

Define Your Scope & Constraints 01 02 03 No compromise to existing product features No slowdown on new product features being built No big rewrites or tech stack changes

Identify The Right Opportunities

Empathize With Your Users Understand common user flows Revenue distribution by browsers & platform Step progression User distribution by browsers/devices/connection Use data to understand user pain points

Audit Your Application Chrome’s Dev Tools WebPageTest & Lighthouse Make the invisible visible Webpack Bundle Analyzer

Apply First Principles

Principles of Web Performance 1 Do only what is needed 2 Minimize round trip time 3 Optimize Perceived Performance

PART 2 7 Key Optimizations

Do only what is needed

Reduce Bundle Size

1 Code Splitting & Lazy Loading “Get it when you need it” Component centric code splitting via dynamic imports (ES2020) TTI 18.2% Code split user/item specific feature code Lazy load components which are below the fold 18.2% Cumulative TTI Improvement

1 Code Splitting - Learnings Aggressive code splitting increased overall bytes downloaded Our sweet spot Duplicates in chunks Reduced Compression 18.2% Cumulative TTI Improvement < 15 split bundles

2 Slim Down Libraries Gains From Switch To Moment.js date-fns 50KB React v15 React v16 15KB React-Intl Custom utility 14KB Recompose React API / Hooks 5KB (compressed) Upgrade from Webpack v3 to v4 reduced bundle size by 10% TTI 9.7% 18.2% 26.1% Cumulative TTI Improvement

3 Differential Serving Enables us to serve modern JS code to users Why do we need it? TTI 3.3% • Transformed ES5 code is verbose (more KB) • Cut down on polyfills needed (~35KB for us) 28.5% 26.1% Cumulative TTI Improvement

3 Differential Serving Module No-Module Pattern 28.5% 26.1% Cumulative TTI Improvement

3 Differential Serving - Learnings Problem On a few browser versions both ES5 & ES6 scripts were downloaded/executed leading to degraded experience for those customers 28.5% 26.1% Cumulative TTI Improvement

3 Differential Serving - Learnings Solution On Server side, we check for the user agent passed and depending on whether the browser supports modern syntax or not we include the right bundle into the page. 28.5% 26.1% Cumulative TTI Improvement

Minimize round trip time

Sharing is caring for our users

4 Shared Bundles Webpack DLL Plugin 1P/3P bundles • Shared across whole site Functional shared bundles • Shared across Cart & Checkout TTI 10.2% 35.8% 25.8% Cumulative TTI Improvement

4 Shared Bundles - Learnings Functional shared bundles 1P/3P shared bundle Needs unification of package versions across applications Updates frequently and requires changes across all shared web-apps Updates to shared bundles require coordination with multiple teams Testing/validations & Release effort 35.8% 28.5% Cumulative TTI Improvement

5 Shared Header/Footer Problem Header/Footer package was bundled into each app leading to bloat Any change required testing/validation & deployments across for all teams

5 Shared Header/Footer Render Header/Footer & rest of the App in parallel during SSR Solution Endpoint returning header/footer HTML Fragment Markup & bundles get cached

5 Shared Header/Footer 70% Optimization reduction in client side JS Reuse existing code and render with React on Server Side TTI 8.1% Use Vanilla JS for handling events on client 41% 35.8% Cumulative TTI improvement

6 Brotli Compression “It’s like GZIP on steroids” 12% smaller bundles than GZIP TTI 9.8% 46.7% 41% Cumulative TTI Improvement

6 Brotli Compression – Learnings Dynamic compression can be slow For Best Perf - Pre-build compressed assets and serve it from a CDN to save the runtime cost. 46.7% 41% Cumulative TTI Improvement

6 Brotli Compression - Learnings For Differential Serving Brotli compressed ES5 bundles pretty well ES6 vs ES5 bundle difference dropped from 10% to 4%* *YMMV 46.7% 41% Cumulative TTI Improvement

Optimize Perceived Performance

7 Leverage Priorities & Resource Hints <script> <script async> defer> HTML parsing Script download HTML parsing paused Script execution TTI 5.7% 49.7% 46.7% Cumulative TTI improvement

7 Leverage Priorities & Resource Hints Tells the browser to download and cache a resource to have them available for execution when it is needed 49.7% 46.7% Cumulative TTI Improvement

7 Leverage Priorities & Resource Hints dns-prefetch preconnect DNS lookup DNS lookup, TLS negotiation, and TCP handshake 49.7% 46.7% Cumulative TTI Improvement

Can we make it faster?

“The fastest HTTP request is the one not made”

8 Prefetch Downloads scripts with lower priority & stores it in prefetch cache TTI 12.1% Cached for at least 5mins Does not execute JS 49.7% 55.8% Cumulative TTI Improvement

8 Prefetch - Learnings Workaround Problem Impacts current page’s load times • We include prefetch tags into the page after onLoad event is fired • We do not prefetch if the user has data saver on 49.7% 55.8% Cumulative TTI Improvement

Video Comparison Before After

Key Takeaways

Perf Optimizations – Key Takeaways Reduce Bundle Size • Code Splitting & Lazy Loading • Slim down libraries • Differential Serving Shared bundles • 1P/3P & functional shared bundles • Header/Footer HTML fragment Font Optimization • Remove unused glyphs & styles • WOFF & WOFF2 for better compression Image • • • Lazy load images WEBP SVG Better compression • Brotli Redux State transfer optimization • Send state to client in an inert tag Priorities & resource hints • Prefer defer over async • dns-prefetch & preconnect • Prefetch Other Cleanup • Code which you have always wanted to delete. You know what they are J 55.8% 60% Cumulative TTI Improvement

Perf Improvements Over Time TTI What you think it was What it actually was Time (months)

Challenges Performance Regressions Time to complete A/B Tests 3rd Party Scripts: Ads, Marketing Tags Cross-team initiatives

PART 3 Guardrails For Performance

Performance Budgets TTFB Speed Index TTI Page Complete

Performance Metrics Per PR Bundle Size check at PR

Performance Metrics Per PR Lighthouse metrics for each PR View perf metrics over time

Compare Metrics Across Branches Teams can compare branch performance to production performance Click through commits and see what caused the degradation Results used to accept or reject release

Sustaining A Performance Culture Embed performance thinking early in the product development process Use tooling and data to help drive decisions on performance tradeoffs Maintain gains by monitoring key metrics, tooling and having guardrails Recognize performance is hard and there will be tradeoffs

The Team Bryan Morgan Denys Mikhalenko Cory Dang Ah Hyun Cho Hiren Patel Madhav Deverkonda Test Armada & Torbit Team Gauri Shankar Rodrigo Delgado Jon Campbell Uma Mahesh Meet Parikh Megha Gupta Patrick Stapleton Vijay Muniswamy

Future Plans 01 Progressive Web App (PWA) 02 Experimenting with alternative UI libraries 03 Streaming SSR 04 Different experiences based on Speed Profiles

Performance Is A Journey, Not A Destination

THANK YOU vasanth_k vasanthk