KEMBAR78
More efficient, usable web | PDF
Doing things better: A more
efficient, usable web?
Chris Mills, :
Who am I?
:
‣ Content lead for MDN (web docs) at
Mozilla
‣ Open web evangelist/hippy
‣ Lover of HTML/CSS/JS
‣ Accessibility whinge bag
‣ Heavy metal drummer
So what are we talking about?
The early days
:
‣ Text
‣ Static
‣ Few form factors
It got better
:
‣ Images AND text!
‣ Dynamic websites
‣ Better, more consistent client-side
tech
‣ Still low power on the client
The modern web is amazing
:
‣ The web on phones, tablets, TVs!
‣ Apps, not pages
‣ The client-side is waaaaay more
complex
Further improvements
:
‣ Efficiency — doing existing things
better
‣ Extensibility — making things more
customizable
‣ Flexibility — allowing the web to
work better across platforms
Streams
A pipe dream…
:
‣ Streaming is nothing new
‣ The browser does it all the time
‣ But why not use it to our advantage?
The Streams API
:
‣ Programatically access streams of
data from the network
‣ Processing chunks one by one
‣ Not having to wait for the whole lot
In addition
:
‣ You can detect when streams start or
end
‣ Cancel streams if required
‣ React to the speed a stream is being
read at
Writing streams
:
‣ You can also write to streams
‣ If you want to modify or generate a
stream to be read somewhere else.
Example
:
// Fetch the original image
fetch('./tortoise.png')
// Retrieve its body as ReadableStream
.then(response => {
const reader = response.body.getReader();
Example
:
return pump();
function pump() {
return reader.read().then(({ done, value }) => {
// When no more data needs to be consumed,
// close the stream
if (done) {
controller.close();
return;
}
// do something with the value here
return pump();
});
}
WebAssembly
Faster code in the browser
:
‣ JavaScript used to be slow
‣ Browser vendors worked hard on this
— V8, SpiderMonkey, etc.
‣ But there is still a limit to how fast JS
can go
A new JavaScript?
:
‣ Some folks from Mozilla came up
with asm.js
‣ A very optimizable subset of JS
‣ And Emscripten, a C++ -> asm.js
compiler
Enter WebAssembly (wasm)
:
‣ A low-level language
‣ Runs in the browser
‣ A compilation target for low-level
languages
Not a JS replacement
:
‣ wasm modules can run alongside JS
‣ Functions can be imported into the
JS runtime
‣ (in the same way as EcmaScript
modules)
Example
:
#include <stdio.h>
int main(int argc, char ** argv) {
printf("Hello Worldn");
}
Example
:
(func $func54 (param $var0 i32) (param
$var1 i32) (param $var2 i32) (result i32)
block (result i32)
i32.const 1
call $import0
i32.const 0
end
)
(func $func55 (param $var0 i32)
i32.const 2
call $import0
)
(data (i32.const 1024)
"0404000005"
Example
:
var importObject = {

imports: { imported_func: arg =>
console.log(arg) }
};
fetch('simple.wasm').then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(obj => {
obj.instance.exports.exported_func();
});
Example
:
var importObject = {

imports: { imported_func: arg =>
console.log(arg) }
};
WebAssembly.instantiateStreaming(fetch('simple.wasm'
), importObject)
.then(obj => obj.instance.exports.exported_func());
Web components
Spaghetti code
:
‣ We write a lot of complex HTML
‣ Custom controls, media players, etc.
‣ This makes a mess in our markup
‣ And we risk conflicts
Frameworks do this
:
‣ But their components are locked in
‣ Can’t be transferred
Web components…
:
‣ …allow us to mitigate this
‣ Define custom elements
‣ With encapsulated DOM/style/script
‣ And flexible templates
Custom elements
:
‣ Can be autonomous (stand alone)
‣ Or customized built-ins (extend
existing elements)
Example
:
class EditWord extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
…
}
}
customElements.define('edit-word', EditWord);
<p>My name is <edit-word>Chris</edit-word>.</p>
Example
:
class WordCount extends HTMLParagraphElement {
constructor() {
// Always call super first in constructor
super();
…
}
}
customElements.define('word-count', WordCount,
{ extends: 'p' });
<p is="word-count"></p>
Shadow DOM
:
‣ Already exists in browsers
‣ Think of a <video> element
Shadow DOM
:
‣ You can attach a shadow root to
certain elements
‣ Inside here, you can encapsulate all
your DOM/style/script
Shadow DOM
:
Example
:
// Create a shadow root and a span node
var shadow = this.attachShadow({mode: 'open'});
var text = document.createElement('span');
// Append span to the shadow root
shadow.appendChild(text);
// We want to count words in element's parent
var wcParent = this.parentNode;
// Update word count regularly
setInterval(function() {
var count = 'Words: ' + countWords(wcParent);
text.textContent = count;
}, 200)
Templates
:
‣ <template> is really useful
‣ Store markup now, add it to the DOM
later
‣ Use templates inside a Shadow DOM
Slots
:
‣ <slot> allows you to define a
placeholder
‣ In a template
‣ That you can fill later with whatever
you want
Example
:
<template id="my-paragraph">
<style>
p {
color: white;
background-color: #666;
padding: 5px;
}
</style>
<p><slot name="my-text">My default text</slot></p>
</template>
Example
:
customElements.define('my-paragraph',
class extends HTMLElement {
constructor() {
super();
let template = document.getElementById('my-paragraph');
let templateContent = template.content;
const shadowRoot = this.attachShadow({mode: 'open'})
.appendChild(templateContent.cloneNode(true));
}
})
Example
:
<my-paragraph>
<span slot="my-text">Some text!</span>
</my-paragraph>
Service workers
The offline web?
:
‣ Hrm.
‣ Still doesn’t work very well offline,
does it?
‣ We had AppCache, but that was
proven to be awful
Service workers
:
‣ Chunks of JS that control pages
‣ Registered against pages
‣ Allow you to create custom
responses
Cache API
:
‣ Works with service workers
‣ (Although it doesn’t have to)
‣ Allows you to cache responses
Example
:
if('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/pwa-examples/a2hs/sw.js')
.then(function() { console.log('Service 

Worker Registered');

});
}
Example
:
self.addEventListener('install', function(e) {
e.waitUntil(
caches.open('video-store').then(function(cache) {
return cache.addAll([
'/pwa-examples/a2hs/',
'/pwa-examples/a2hs/index.html',
'/pwa-examples/a2hs/index.js',
'/pwa-examples/a2hs/style.css',
…
]);
})
);
});
Example
:
self.addEventListener('fetch', function(e) {
console.log(e.request.url);
e.respondWith(
caches.match(e.request).then(function(response)
{
return response || fetch(e.request);
})
);
});
SW use cases
:
‣ Offlining web sites using Cache
‣ Client-side compilation
‣ Handling push messages
‣ Custom templating
‣ Background synchronization
‣ On-the-fly polyfilling…
PWAs
Competing with native
:
‣ That age old battle
‣ We’ve largely got tech parity
‣ What we need is UX parity too
The native experience
:
‣ Installing offline
‣ Homescreen icons
‣ Occupying fullscreen
Progressive web apps
:
‣ Provide all of this
‣ While still using the strengths of the
web
Offline
:
‣ Store data offline using IndexedDB,
Web Storage, etc.
‣ Store assets offline using Service
workers + Cache API.
Homescreen/fullscreen
:
‣ Controlled using the web manifest
‣ “Add to homescreen” (A2HS)
supported in Fx/Chrome
Example
:
{

…
"display": "fullscreen",
"icons": [
{
"src": "icon/fox-icon.png",
"sizes": "192x192",
"type": "image/png"
}
],
"name": "Awesome fox pictures",
"short_name": "Foxes",
"start_url": "/pwa-examples/a2hs/index.html"
}
Finished!
Chris Mills, :
cmills@:.com | @chrisdavidmills
Credits
:
‣ Shipping containers photo by Glyn Lowe
‣ Max headroom stolen from a syfy.com article
‣ IE2 image from geek.com
‣ Pipes photo by Matt
‣ Circuit board photo by Phil Norton
‣ Component bricks photo by Sondra
‣ Brain photo by Like_the_Grand_Canyon

More efficient, usable web