FUN WITH SERVICE WORKERS @TRENTMWILLIS

ATWOOD’S LAW "ANY APPLICATION THAT CAN BE WRITTEN IN JAVASCRIPT, WILL EVENTUALLY BE WRITTEN IN JAVASCRIPT.”

FUN WITH SERVICE WORKERS

@TRENTMWILLIS

LOVE THE WEB LOVE JAVASCRIPT @TRENTMWILLIS

JAVASCRIPT CONTINUES TO EVOLVE @TRENTMWILLIS

WEB HYPERTEXT APPLICATION TECHNOLOGY WORKING GROUP @TRENTMWILLIS

WHATWG @TRENTMWILLIS

STREAMS SPEC “IF INSTALLED INSIDE THE FETCH HOOK OF A SERVICE WORKER, THIS WOULD ALLOW DEVELOPERS TO TRANSPARENTLY POLYFILL NEW IMAGE FORMATS.” @TRENTMWILLIS

POLYFILLING FILE FORMATS @TRENTMWILLIS

New Image Format @TRENTMWILLIS

New Image Format <img src=“./my-image.nif”> @TRENTMWILLIS

New Image Format <img src=“./my-image.nif”> *Can Display PNG/JPEG/GIF, Not NIF @TRENTMWILLIS

New Image Format Service Worker <img src=“./my-image.nif”> *Can Display PNG/JPEG/GIF, Not NIF @TRENTMWILLIS

New Image Format .nif Service Worker .gif <img src=“./my-image.nif”> *Can Display PNG/JPEG/GIF, Not NIF @TRENTMWILLIS

ALL CODE WILL BE AVAILABLE ONLINE @TRENTMWILLIS

navigator.serviceWorker.register(‘./service-worker.js’); @TRENTMWILLIS

self.addEventListener('fetch', (event) => {; }); @TRENTMWILLIS

self.addEventListener('fetch', (event) => {; event.respondWith(); }); @TRENTMWILLIS

self.addEventListener('fetch', (event) => {; event.respondWith(validFileFromPolyfilledFile(event.request)); }); @TRENTMWILLIS

self.addEventListener('fetch', (event) => {; if (isPolyfilledFile(event.request)) { event.respondWith(validFileFromPolyfilledFile(event.request)); validFileFromPolyfilledFile }; }); @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => { }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => { const originalResponse = await fetch(request); }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => { const originalResponse = await fetch(request); const originalData = originalResponse.blob(); // .text(), .json(), etc. }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => { const originalResponse = await fetch(request); const originalData = originalResponse.blob(); // .text(), .json(), etc. const modifiedData = polyfillTransform(originalData); }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => { const originalResponse = await fetch(request); const originalData = originalResponse.blob(); // .text(), .json(), etc. const modifiedData = polyfillTransform(originalData); const modifiedResponse = new Response(modifiedData); return modifiedResponse; }; @TRENTMWILLIS

cryptogram-naive.glitch.me @TRENTMWILLIS

html-modules-polyfill.glitch.me @TRENTMWILLIS

COMPILING CODE AT RUNTIME @TRENTMWILLIS

TYPESCRIPT AT RUNTIME @TRENTMWILLIS

<script src="my-module.ts"></script>

@TRENTMWILLIS

<script src="my-module.ts" type="module"></script>

@TRENTMWILLIS

CACHE API @TRENTMWILLIS

ONLY COMPILE CHANGED FILES @TRENTMWILLIS

const compileWithCache = async (response, compile) => { }; @TRENTMWILLIS

const compileWithCache = async (response, compile) => { const cache = await caches.open(‘compile-cache'); }; @TRENTMWILLIS

const compileWithCache = async (response, compile) => { const cache = await caches.open(‘compile-cache'); if (response.headers.get('status') === '304') { }; }; @TRENTMWILLIS

const compileWithCache = async (response, compile) => { const cache = await caches.open(‘compile-cache'); if (response.headers.get('status') === '304') { return cache.match(request.url); }; }; @TRENTMWILLIS

const compileWithCache = async (response, compile) => { const cache = await caches.open(‘compile-cache'); if (response.headers.get('status') === '304') { return cache.match(request.url); }; const compiledResponse = compile(response); }; @TRENTMWILLIS

const compileWithCache = async (response, compile) => { const cache = await caches.open(‘compile-cache'); if (response.headers.get('status') === '304') { return cache.match(request.url); }; const compiledResponse = compile(response); cache.put(request.url, compiledResponse.clone()); }; @TRENTMWILLIS

const compileWithCache = async (response, compile) => { const cache = await caches.open(‘compile-cache'); if (response.headers.get('status') === '304') { return cache.match(request.url); }; const compiledResponse = compile(response); cache.put(request.url, compiledResponse.clone()); return compiledResponse; }; @TRENTMWILLIS

typescript-in-browser.glitch.me @TRENTMWILLIS

OFF THE MAIN THREAD DATA PROCESSING @TRENTMWILLIS

API JS @TRENTMWILLIS Process Here

API Service Worker UI @TRENTMWILLIS Process Here

API Service Worker Process Here UI @TRENTMWILLIS

API Web Worker Service Worker UI @TRENTMWILLIS Process Here

const transform = async (request, clientId) => { const [response, port] = await Promise.all([ fetch(request), getPortToWebWorkerFromClient(clientId) getPortToWebWorkerFromClient ]); }; @TRENTMWILLIS

const getPortToWebWorkerFromClient = async (clientId) => { const client = await self.clients.get(clientId); }; @TRENTMWILLIS

const getPortToWebWorkerFromClient = async (clientId) => { const client = await self.clients.get(clientId); return new Promise(resolve => { }); }; @TRENTMWILLIS

const getPortToWebWorkerFromClient = async (clientId) => { const client = await self.clients.get(clientId); return new Promise(resolve => { client.postMessage({}); }); }; @TRENTMWILLIS

const webWorker = new Worker('web-worker.js'); navigator.serviceWorker.onmessage = () => { }; @TRENTMWILLIS

const webWorker = new Worker('web-worker.js'); navigator.serviceWorker.onmessage = () => { const channel = new MessageChannel(); }; @TRENTMWILLIS

const webWorker = new Worker('web-worker.js'); navigator.serviceWorker.onmessage = () => { const channel = new MessageChannel(); const serviceWorker = navigator.serviceWorker.controller; serviceWorker.postMessage({port: channel.port1}, [channel.port1]); }; @TRENTMWILLIS

const webWorker = new Worker('web-worker.js'); navigator.serviceWorker.onmessage = () => { const channel = new MessageChannel(); const serviceWorker = navigator.serviceWorker.controller; serviceWorker.postMessage({port: channel.port1}, [channel.port1]); webWorker.postMessage({port: channel.port2}, [channel.port2]); }; @TRENTMWILLIS

const getPortToWebWorkerFromClient = async (clientId) => { const client = await self.clients.get(clientId); return new Promise(resolve => { client.postMessage({}); }); }; @TRENTMWILLIS

const getPortToWebWorkerFromClient = async (clientId) => { const client = await self.clients.get(clientId); return new Promise(resolve => { self.onmessage = (msg) => { self.onmessage = null; resolve(msg.data.port); }; client.postMessage({}); }); }; @TRENTMWILLIS

const transform = async (request, clientId) => { const [response, port] = await Promise.all([ fetch(request), getPortToWebWorkerFromClient(clientId) ]); }; @TRENTMWILLIS

const transform = async (request, clientId) => { const [response, port] = await Promise.all([ fetch(request), getPortToWebWorkerFromClient(clientId) ]); return new Promise(async (resolve) => { }); }; @TRENTMWILLIS

const transform = async (request, clientId) => { const [response, port] = await Promise.all([ fetch(request), getPortToWebWorkerFromClient(clientId) ]); return new Promise(async (resolve) => { port.postMessage(await response.json()); }); }; @TRENTMWILLIS

const transform = async (request, clientId) => { const [response, port] = await Promise.all([ fetch(request), getPortToWebWorkerFromClient(clientId) ]); return new Promise(async (resolve) => { port.onmessage = (msg) => { resolve(new Response([${msg.data.toString()}])); }; port.postMessage(await response.json()); }); }; @TRENTMWILLIS

service-worker-worker.glitch.me @TRENTMWILLIS

STREAM DATA PROCESSING @TRENTMWILLIS

Original Data @TRENTMWILLIS Modified Data

BATCH BATCH DIGRA PROCESSING Encrypted Chunk Encrypted Chunk Decrypted Chunk @TRENTMWILLIS Encrypted Chunk Decrypted Chunk Encrypted Chunk Decrypted Chunk Encrypted Chunk Decrypted Chunk Encrypted Chunk Decrypted Chunk Decrypted Chunk

STREAM BATCH DIGRA PROCESSING Encrypted Chunk Encrypted Chunk Decrypted Chunk @TRENTMWILLIS Encrypted Chunk Decrypted Chunk Encrypted Chunk Decrypted Chunk Encrypted Chunk Decrypted Chunk Encrypted Chunk Decrypted Chunk Decrypted Chunk

Data Chunk Data Chunk Modified Chunk @TRENTMWILLIS Data Chunk Modified Chunk Data Chunk Modified Chunk Data Chunk Modified Chunk Data Chunk Modified Chunk Modified Chunk

Original Data Data Chunk Data Chunk Modified Chunk Data Chunk Modified Chunk @TRENTMWILLIS Modified Data Data Chunk Modified Chunk Data Chunk Modified Chunk Data Chunk Modified Chunk Modified Chunk

const validFileFromPolyfilledFile = async (request) => { const originalResponse = await fetch(request); const originalData = originalResponse.blob(); // .text(), .json(), etc. const modifiedData = polyfillTransform(originalData); const modifiedResponse = new Response(modifiedData); return modifiedResponse; }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => {; const originalResponse = await fetch(request); const transformStream = new TransformStream(new Transformer()); const transformedBody = originalResponse.body.pipeThrough( transformStream ); const transformedResponse = new Response(transformedBody); return transformedResponse; }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => {; const originalResponse = await fetch(request); const transformStream = new TransformStream(new Transformer()); const transformedBody = originalResponse.body.pipeThrough( transformStream ); const transformedResponse = new Response(transformedBody); return transformedResponse; }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => {; const originalResponse = await fetch(request); const transformStream = new TransformStream(new Transformer()); const transformedBody = originalResponse.body.pipeThrough( transformStream ); const transformedResponse = new Response(transformedBody); return transformedResponse; }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => {; const originalResponse = await fetch(request); const transformStream = new TransformStream(new Transformer()); const transformedBody = originalResponse.body.pipeThrough( transformStream ); const transformedResponse = new Response(transformedBody); return transformedResponse; }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => {; const originalResponse = await fetch(request); const transformStream = new TransformStream(new Transformer()); const transformedBody = originalResponse.body.pipeThrough( transformStream ); const transformedResponse = new Response(transformedBody); return transformedResponse; }; @TRENTMWILLIS

const validFileFromPolyfilledFile = async (request) => {; const originalResponse = await fetch(request); const transformStream = new TransformStream(new Transformer()); Transformer const transformedBody = originalResponse.body.pipeThrough( transformStream ); const transformedResponse = new Response(transformedBody); return transformedResponse; }; @TRENTMWILLIS

class Transformer {; async start() {}; async transform() {}; async flush() {}; }; @TRENTMWILLIS

cryptogram-streaming.glitch.me @TRENTMWILLIS

POLYFILLING FILE FORMATS SERVICE WORKERS COMPILING CODE AT RUNTIME WEB ASSEMBLY OFF THE MAIN THREAD DATA PROCESSING STREAM DATA PROCESSING @TRENTMWILLIS STREAMS ESNEXT WEB COMPONENTS AND MORE!

EXPERIMENT & HAVE FUN WITH JAVASCRIPT! *ALSO, GLITCH IS GREAT FOR EXPERIMENTS! @TRENTMWILLIS

QUESTIONS? @TRENTMWILLIS