jrjohnson
jrjohnson_
Slides at: https://jrjohnson.dev/talks/2018-10-ready-set-go-sflive.html
A single-page application (SPA) is a web application or web site that fits on a single web page with the goal of providing a more fluid user experience akin to a desktop application. In a SPA, either all necessary code – HTML, JavaScript, and CSS – is retrieved with a single page load,[1] or the appropriate resources are dynamically loaded and added to the page as necessary, usually in response to user actions. The page does not reload at any point in the process, nor does control transfer to another page, although modern web technologies (such as those included in the HTML5 pushState() API) can provide the perception and navigability of separate logical pages in the application. Interaction with the single page application often involves dynamic communication with the web server behind the scenes.
A single-page application (SPA) is a web application or web site that fits on a single web page with the goal of providing a more fluid user experience akin to a desktop application. In a SPA, either all necessary code – HTML, JavaScript, and CSS – is retrieved with a single page load, or the appropriate resources are dynamically loaded and added to the page as necessary, usually in response to user actions. The page does not reload at any point in the process, nor does control transfer to another page, although modern web technologies (such as those included in the HTML5 pushState() API) can provide the perception and navigability of separate logical pages in the application. Interaction with the single page application often involves dynamic communication with the web server behind the scenes.
A single-page application (SPA) is a web application or web site that fits on a single web page with the goal of providing a more fluid user experience akin to a desktop application. In a SPA, either all necessary code – HTML, JavaScript, and CSS – is retrieved with a single page load, or the appropriate resources are dynamically loaded and added to the page as necessary, usually in response to user actions. The page does not reload at any point in the process, nor does control transfer to another page, although modern web technologies (such as those included in the HTML5 pushState() API) can provide the perception and navigability of separate logical pages in the application. Interaction with the single page application often involves dynamic communication with the web server behind the scenes.
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>EmberDemo</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="ember-demo/config/environment" content="%7B%22modulePrefix%22%3A%22ember-demo%22%2C%22environment%22%3A%22development%22%2C%22rootURL%22%3A%22/%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%7D%2C%22APP%22%3A%7B%22name%22%3A%22ember-demo%22%2C%22version%22%3A%220.0.0+8c9fd3a5%22%7D%2C%22exportApplicationGlobal%22%3Atrue%7D" /> <link integrity="" rel="stylesheet" href="/assets/vendor.css"> <link integrity="" rel="stylesheet" href="/assets/ember-demo.css"> </head> <body> <script src="/assets/vendor.js"></script> <script src="/assets/ember-demo.js"></script> </body></html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <link rel="manifest" href="/manifest.json"> <link rel="shortcut icon" href="/favicon.ico"> <title>React App</title> </head> <body> <noscript> You need to enable JavaScript to run this app. </noscript> <div id="root"></div> <script type="text/javascript" src="/static/js/bundle.js"></script></body> </html>
<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="/favicon.ico"> <title>Vue Demo</title> <link href="/app.js" rel="preload" as="script"></head> <body> <noscript> <strong>We're sorry but Vue Demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <script type="text/javascript" src="/app.js"></script></body></html>
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>AngularDemo</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root></app-root> <script type="text/javascript" src="runtime.js"></script> <script type="text/javascript" src="polyfills.js"></script> <script type="text/javascript" src="styles.js"></script> <script type="text/javascript" src="vendor.js"></script> <script type="text/javascript" src="main.js"></script></body> </html>
<!DOCTYPE html><html> <head> <link rel="stylesheet" href="/build/app.css"> </head> <body> <script src="/build/app.js"></script> </body></html>
The second visit is the most fun, we get to play so many fun tricks on the seconds visit. Cached content, service workers, some real magix to speed up the trip, But the first visit is where the Money is. When a dean is evaluating out product they might only spend 15 minutes clicking around. They're not coming back tomorrow. The first visit has to be smooth.
<link href="app.css">
<link href="{{ preload(asset('app.css'), { as: 'style' }) }}">
Also worth considering a CDN for some assets if your users are not necessarily located near the server.
<html> <head> <link rel="stylesheet" href="/assets/app.css"> </head> <body> <script src="/assets/framework.js"></script> <script src="/assets/app.js"></script> </body></html>
<html> <head> <link rel="stylesheet" href="/assets/app.css"> </head> <body> <!-- LOADING INDICATOR--> <h1>We'll be right with you... Promise!</h1> <!-- /LOADING INDICATOR--> <script src="/assets/framework.js"></script> <script src="/assets/app.js"></script> </body></html>
<html> <head> <!-- WAIT --><link rel="stylesheet" href="/assets/app.css"> </head> <body> <!-- WAIT --><h1>We'll be right with you... Promise!</h1> <!-- WAIT --><script src="/assets/framework.js"></script> <!-- WAIT --><script src="/assets/app.js"></script> </body></html>
<html> <head> </head> <body> <style> h1 { color: orange; font-size: 3rem; } </style><!-- WAIT --> <!-- WAIT --><h1>We'll be right with you... Promise!</h1> <!-- WAIT --><link rel="stylesheet" href="/assets/app.css"> <!-- WAIT --><script src="/assets/framework.js"></script> <!-- WAIT --><script src="/assets/app.js"></script> </body></html>
rel="stylesheet"
can be in the body https://html.spec.whatwg.org/multipage/links.html#body-ok <body> <style> h1 { color: orange; font-size: 3rem; } </style> <h1>We'll be right with you... Promise!</h1> <!-- wait --><link rel="stylesheet" href="/assets/app.css"> <script defer src="/assets/framework.js"></script> <script defer src="/assets/app.js"></script> </body>
<link rel="stylesheet" href="/assets/app.css"><noscript>This Site Requires Javascript!</noscript>
<h1 id='loading-indicator'>and we're spinning...</h1><h1 class='hidden' id='loading-error'>Whoops!</h1>
window.addEventListener('error', function () { var loadingIndicator = document.getElementById('loading-indicator'); if (loadingIndicator) { loadingIndicator.parentNode.removeChild(loadingIndicator); } var errorContainer = document.getElementById('loading-error'); if (errorContainer) { errorContainer.classList.remove('hidden'); }});
$response = new Response();$response->setMaxAge(60 * 60 * 24 * 365);// Cache-Control: max-age=31536000, public
$response = new Response();$response->setMaxAge(60 * 60 * 24 * 365);// Cache-Control: max-age=31536000, public
$response = new Response();$response->setEtag(sha1($content));$response->headers->addCacheControlDirective('no-cache');$response->isNotModified($request);// Cache-Control: no-cache, public// ETag: "2bff8fd31f3a1f11275cd2cff55a0491e2e62da4"
self.addEventListener('fetch', event => { event.respondWith(caches.match('/index.html').then(response => { if (response) { return response; } }));});
self.addEventListener('install', () => { // Activate this worker right now, removing other workers self.skipWaiting();});
Progressive Web Apps are installable and live on the user's home screen, without the need for an app store. They offer an immersive full screen experience with help from a web app manifest file and can even re-engage users with web push notifications.
jrjohnson
jrjohnson_
Slides at: https://jrjohnson.dev/talks/2018-10-ready-set-go-sflive.html
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |