WHEN JAVASCRIPT BYTES Tim Kadlec @tkadlec #perfnow

4kb RAM 74kb ROM

.1%

<1.7mb

<1.7mb 1.8mb

B M 2 . 4

Network

Desktop Mobile 96.2kb 84.4kb p10 204.5kb 180.2kb p25 412.6kb 378.6kb p50 753.6kb 694.8kb p75 1,180.5kb 1,099.0kb p90 0 300 600 900 Kilobytes of JavaScript 1200

@KenjiBaheux

@KenjiBaheux

16% Brotli 17% Uncompressed 67% GZip

16% Brotli 17% Uncompressed 67% GZip

npm install compression-webpack-plugin —save-dev //webpack config file new CompressionPlugin({ test: /.js(?.)?$/i, algorithm: ‘brotliCompress’, filename: ‘[file].br’, compressionOptions: { level: 11 }, minRatio: 1, }), new CompressionPlugin({ test: /.js(?.)?$/i, filename: ‘[file].gz’, minRatio: 1, })

Brotli provides ~20% improvement over GZip But…

“We tried it in prod with our @nuxt_js project and our response times went from 300ms to over 12 seconds! Scaling exploded.” Josh Deltener, @hecktarzuli https://twitter.com/hecktarzuli/status/1163887824514539522

10-20% Fewer bytes 20% Fewer bytes ~3.6% Page load 0% Page load

On Device

Desktop Mobile 96.2kb 84.4kb p10 204.5kb 180.2kb p25 412.6kb 378.6kb p50 753.6kb 694.8kb p75 1,180.5kb 1,099.0kb p90 0 300 600 900 Kilobytes of JavaScript 1200

Desktop Mobile 481.0kb 421.9kb p10 1,022.3kb 901.2kb p25 2,063.0kb 1,892.5kb p50 3,768.0kb 3,474.1kb p75 5,902.5kb 5,495.1kb p90 0 1500 3000 4500 Kilobytes of JavaScript 6000

Desktop Mobile 144ms 466ms 365ms 1,372ms 918ms p10 p25 p50 3,437ms 2,015ms p75 7,757ms 3,848ms p90 14,705ms 0 4000 8000 12000 Mainthread Processing Time 16000

466ms 843ms 1,515ms 3,489ms p10 All Vue jQuery React 3,437ms 3,824ms 5,726ms p50 11,634ms 14,705ms 14,879ms p90 18,259ms 28,027ms 0 7500 15000 22500 Mainthread Processing Time 30000

var observer = new PerformanceObserver(function(list) { var perfEntries = list.getEntries(); for (var i = 0; i < perfEntries.length; i++) { //queue it up to be sent back for tracking } }); observer.observe({entryTypes:[‘longtask’]});

200ms 20ms 40ms 150ms 300ms 15ms 100ms

Number of Long Tasks 200ms 1 20ms 40ms 150ms 2 300ms 3 15ms 100ms 4

Longest Long Task 200ms 20ms 40ms 150ms 300ms 300ms 15ms 100ms

Long Tasks Time 200ms 20ms 40ms JS CPU Time 150ms 300ms 15ms 100ms 200+150+300+100 = 750

Total Blocking Time 200ms 20ms 40ms 150ms 300ms 15ms 100ms 150+100+250+50 = 550

19S 65S PIXEL 2 ALCATEL 1X

HOW MUCH IS TOO MUCH?

32 MONTHS

$214

85%

ANDROID > 1 YEAR OLD < $200

ANDROID > 1 YEAR OLD < $200 SLOW 3G 400MS RTT 4000KBPS TRANSFER @slightlylate

130-170KB CRITICAL PATH RESOURCES @slightlylate

~100KB

HTML

HTML a.js

HTML Parse/Compile a.js a.js Execute a.js

HTML Parse/Compile a.js a.js Execute a.js

HTML Execute a.js a.js Parse/Compile a.js

HTML Execute a.js a.js (200kb) Parse/Compile a.js

HTML Execute a.js a.js (200kb) Parse/Compile a.js

HTML Execute a.js a.js (200kb) Parse/Compile a.js B K 0 3

HTML Execute a.js a.js (200kb) Parse

HTML Execute a.js a.js (200kb) Parse

HTML Execute a.js a.js Parse b.js Parse Execute b.js

HTML Execute a.js a.js Parse b.js Parse Execute b.js

50-100KB PER BUNDLE

50-100KB ~100KB PER BUNDLE TOTAL

487kb (2.6MB)

import { config, CognitoIdentityServiceProvider } from ‘aws-sdk’;

const CognitoIdentityServiceProvider = require(‘aws-sdk/clients/ cognitoidentityserviceprovider’);

<1.65MB

external: [‘apollo-client’, ‘apollo-link’, ‘graphql-tag’],

<15KB

resolve: { alias: { “core-js”: path.resolve(__dirname, ‘node_modules/core-js’) }, },

externals : [ { “vue-swiper-js”: “vue-swiper-js”, “vuelidate”: “vuelidate”, “vuelidate/lib/validators”: “vuelidate/lib/validators”, } ],

<59.5KB

2.6MB 898.3KB 66% reduction

MAINTAIN & ITERATE

Warned or blocked on install Warned or blocked in code editor Blocked on PR Blocked on deploy Tracked on deploy

DEFAULT STANCE MATTERS

WE’VE BUILT A WEB THAT LARGELY DISMISSES AFFORDABLE, TYPICAL SMARTPHONES AND THE PEOPLE THAT USE THEM.

BECAUSE WE CAN

THANK YOU! Tim Kadlec @tkadlec #perfnow