Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Once you go PRPL: SeattleJS
Search
Houssein Djirdeh
August 11, 2017
200
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Once you go PRPL: SeattleJS
Houssein Djirdeh
August 11, 2017
More Decks by Houssein Djirdeh
See All by Houssein Djirdeh
Performance Empathy
housseindjirdeh
0
220
The Art of Lazy Loading
housseindjirdeh
0
580
GitPoint - Lunch and Learn
housseindjirdeh
0
130
Progressive Web Apps - fullStackTO/FITC Web Unleashed
housseindjirdeh
0
230
Once you go PRPL - FullStackFest
housseindjirdeh
0
46
Featured
See All Featured
Designing for Timeless Needs
cassininazir
1
430
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
240
How GitHub (no longer) Works
holman
316
150k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
GitHub's CSS Performance
jonrohan
1033
470k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.2k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
190
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
470
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Marketing to machines
jonoalderson
1
5.6k
Transcript
XKCD/Installing
Once you go PRPL… @hdjirdeh
None
None
None
CSS JS PNG
<link rel="preload" as="script" href="script.js"> <link rel="preload" as="script" href="script.js"> <html lang="en">
<head> <link rel="stylesheet" href="styles.css"> </head> <body> <!--(>'-')> <('-'<)--> <script src="script.js"></script> </body> </html>
<link rel="preload" as="script" href="script.js">
JS JS
<link rel="preload" as="script" href="script.js"> as="script" <link rel="preload" as="style" href="styles.css"> as="style"
as="font" as="audio" as="image" as="video"
as="script" as="style"
as="script" as="style" as="font" as="audio" as="image" as="video"
<link rel="prefetch">
preload-webpack-plugin <link rel="preload" href="chunk.cf7bd8260d685f704bd0.js" as="script"> <link rel="prefetch" href="chunk.cf7bd8260d685f704bd0.js">
CAN I HAZ? Partial Support
HTTP/2 Server Push
None
Link: </app/style.css>; rel=preload; as=style Link: </app/script.js>; rel=preload; as=script
None
Link: </app/style.css>; rel=preload; as=style; nopush Link: </app/script.js>; rel=preload; as=script
A Comprehensive Guide To HTTP/2 Server Push - Jeremy Wagner
https://rebrand.ly/http2
Pushing too much Pushing unused assets Cache?
PUSH critical resources
None
Service workers
A service worker is a script that runs in the
background of your browser when you view a webpage.
ADDING A SERVICE WORKER 1. Create the file and write
the logic yourself 2. Use a library
None
npm install workbox-cli --global workbox-cli generate:sw
None
<script> if ('serviceWorker' in navigator) { window.addEventListener('load', function () {
navigator.serviceWorker.register('/service-worker.js').then(function(){ // Registration was successful console.log('ServiceWorker registration successful!'); }).catch(function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }); }); } </script> if ('serviceWorker' in navigator) { window.addEventListener('load', function () { navigator.serviceWorker.register('/service-worker.js') <script> if ('serviceWorker' in navigator) { window.addEventListener('load', function () { navigator.serviceWorker.register('/service-worker.js').then(function(){ // Registration was successful console.log('ServiceWorker registration successful!'); }).catch(function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }); }); } </script> <script> if ('serviceWorker' in navigator) { window.addEventListener('load', function () { navigator.serviceWorker.register('/service-worker.js').then(function(){ // Registration was successful console.log('ServiceWorker registration successful!'); }).catch(function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }); }); } </script>
None
APPLICATION SHELL
APPLICATION SHELL CONTENT
module.exports = { globDirectory: 'dist/', globPatterns: ['**/*.{js,png,svg,html,json}'], swDest: 'dist/service-worker.js', navigateFallback:
'/index.html' }; module.exports = { globDirectory: 'dist/', globPatterns: ['**/*.{js,png,svg,html,json}'], swDest: 'dist/service-worker.js', navigateFallback: '/index.html', }; module.exports = { globDirectory: 'dist/', globPatterns: ['**/*.{js,png,svg,html,json}'], swDest: 'dist/service-worker.js', navigateFallback: '/index.html' }; globDirectory: 'dist/' globPatterns: ['**/*.{js,png,svg,html,json}'] swDest: 'dist/service-worker.js' navigateFallback: '/index.html'
BUILD PROCESS
npm install workbox-cli --save-dev // package.json "scripts": { //... "build":
"{build} && workbox-cli generate:sw" }
workbox-webpack-plugin
DYNAMIC CONTENT
module.exports = { globDirectory: 'dist/', globPatterns: ['**/*.{js,png,svg,html,json}'], swDest: 'dist/service-worker.js', navigateFallback:
'/index.html', runtimeCaching: [ { urlPattern: /^https:\/\/your.api.com\/.*/, handler: 'networkFirst' } ] }; module.exports = { globDirectory: 'dist/', globPatterns: ['**/*.{js,png,svg,html,json}'], swDest: 'dist/service-worker.js', navigateFallback: '/index.html', runtimeCaching: [ { urlPattern: /^https:\/\/your.api.com\/.*/, handler: 'networkFirst' } ] }; runtimeCaching: [ { urlPattern: /^https:\/\/your.api.com\/.*/, handler: 'networkFirst' } ] runtimeCaching: [ { urlPattern: /^https:\/\/your.api.com\/.*/, handler: 'networkFirst' } ] networkFirst
runtimeCaching: [ { urlPattern: /^https:\/\/your.api.com\/.*/, handler: 'networkFirst' } ] module.exports
= { globDirectory: 'dist/', globPatterns: ['**/*.{js,png,svg,html,json}'], swDest: 'dist/service-worker.js', navigateFallback: '/index.html', runtimeCaching: [ { urlPattern: /^https:\/\/your.api.com\/.*/, handler: 'networkFirst' } ] }; runtimeCaching: [ { urlPattern: /^https:\/\/your.api.com\/.*/, handler: 'networkFirst' } ] networkFirst
networkFirst
networkFirst cacheFirst fastest cacheOnly networkOnly
APP SHELL + DYNAMIC CACHING
OFFLINE SUPPORT + FASTER REPEAT VISITS
CAN I HAZ? Under development
Service Worker H2 Push
PRE-CACHE resources
BUNDLES
4KB - 145KB Size of JS frameworks, gzipped Restuta/framework-sizes.md GIST
CODE SPLITTING
export const routes: Routes = [ { path: '', redirectTo:
'main', pathMatch: 'full' }, { path: 'main', component: MainComponent }, { path: 'details', loadChildren: 'details/details.module#DetailsModule' } ]; export const routes: Routes = [ { path: '', redirectTo: 'main', pathMatch: 'full' }, { path: 'main', component: MainComponent }, { path: 'details', loadChildren: 'details/details.module#DetailsModule' } ]; loadChildren: 'details/details.module#DetailsModule'
import Loadable from 'react-loadable'; import Loading from './loading.component'; const LoadableComponent
= Loadable({ loader: () => import('./details.component'), loading: Loading, });
None
WEBPACK BUNDLE ANALYZER
bundlesize
LAZY LOAD remaining routes
PRPL PUSH critical resources RENDER initial route PRE-CACHE resources LAZY
LOAD remaining routes
Native Progressive Web
TIME TO INTERACTIVE
None
ADDITIONAL developers.google.com/web/tools/lighthouse Lighthouse webpagetest.org/easy WebPageTest ebidel/lighthouse-ci hnpwa.com HNPWA
@hdjirdeh