So...

FrontEnd is just Buttons?

When I was finishing University I thought FrontEnd is not real programming....

I wanted to do this

🔥🔥🔥

NOT THIS! 😡

but actually...

FrontEnd, how hard can it be?

To show you that FrontEnd is not just buttons...

 

...let's look behind the scenes of an open-source app, and see how it's built.

Architecture

CODECS

AVIF

MozJPEG

WebP

...

WEB
WORKER
SERVICE
WORKER
CANVAS
PREACT
CLIENT
ROLLUP

WASM

CODECS

AVIF

MozJPEG

WebP

...

WEB
WORKER
SERVICE
WORKER
CANVAS
PREACT
CLIENT

WASM

ROLLUP

WASM is a way to run programming languages (other than JavaScript) into the browser.

#include <iostream>
using namespace std;
  
int main(int argc, char** argv)
{
    cout << "You have entered " << argc
         << " arguments:" << "\n";
  
    for (int i = 0; i < argc; ++i)
        cout << argv[i] << "\n";
  
    return 0;
}
hello.wasm
hello.js

✔️ Squoosh.app encodes images to different formats using C++ code converted to Web Assembly.

CODECS

AVIF

MozJPEG

WebP

...

WEB
WORKER
SERVICE
WORKER
CANVAS
PREACT
CLIENT

WASM

ROLLUP

JavaScript code that runs independently (separate thread) from the browser.

✔️ Perfect for doing intensive work in a non-blocking fashion

// Main App
let myWorker = new Worker("worker.js");

myWorker.postMessage("Here's some data");

myWorker.addEventListener("message", (e) => {
  // ...
});
// worker.js
self.addEventListener("message", (e) => {
    // ...
    // ...
    self.postMessage(/* ... */);
});
// Main App
const worker = new Worker('math-worker.js');

worker.postMessage({
  type: 'add',
  values: [Math.random(), Math.random()]
});

worker.addEventListener('message', (e) => {
  switch (e.data.type) {
    case 'result':
      console.log(`Result from Worker is: ${e.data.value}`);
      break;
    default:
      console.warn('[addEventListener] Unknown message type', e.type);
      break;
  }
});
// Worker
self.addEventListener('message', (e) => {
  switch (e.data.type) {
    case 'add':
      self.postMessage({ 
        type: 'result', 
        value: sum(e.data.values) 
      });
      break;
    default:
      console.warn('[self.addEventListener] Unknown message type', e.type);
      break;
  }
});

function sum(numbers) {
  let result = 0;
  numbers.forEach(x => { result += x; })

  return result;
}

💡 Notice the bottom-right spinner. That indicates the image is being encoded. While that happens the rest of the website stays fully responsive.

✔️ Squoosh.app uses Web Workers to convert the images off the main thread. This way, the website stays responsive.

CODECS

AVIF

MozJPEG

WebP

...

WEB
WORKER
SERVICE
WORKER
CANVAS
PREACT
CLIENT

WASM

ROLLUP

Imagine an empty piece of paper where you can programmatically draw anything, pixel by pixel.

✔️ Useful for custom visualizations, maps or games.

let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");

ctx.beginPath();
ctx.rect(10, 100, 50, 50);
ctx.closePath();

ctx.fill();
<body>
  <canvas id="canvas"></canvas>
</body>

Animating the Canvas

window.requestAnimationFrame(onFrame);

On each frame

re-draw the canvas

function onFrame() {
  drawRectangle(xPos, CONFIG.y, direction);

  xPos += direction;

  if (xPos === canvas.width - 50) {
    direction = -1;
  }

  if (xPos === 0) {
    direction = 1;
  }

  window.requestAnimationFrame(onFrame);
}

✔️ Squoosh.app uses two Canvases, one for each side of the comparison.

CODECS

AVIF

MozJPEG

WebP

...

WEB
WORKER
SERVICE
WORKER
CANVAS
PREACT
CLIENT

WASM

ROLLUP

Preact is a fast, 3KB alternative to React with the same modern API.

✔️ When you want actually want to use React but payload size is very important to you.

<body>
  <div>
    <p>
      The counter is 
      <span id="counter">0</span>
    </p>
    <button id="decreaseButton" type="button">
      Decrease
    </button>
    <button id="increaseButton" type="button">
      Increase
    </button>
  </div>
</body>
let counterValue = 0;

const counterDisplayElement = document.getElementById("counter");
const decreaseButton = document.getElementById("decreaseButton");
const increaseButton = document.getElementById("increaseButton");

decreaseButton.addEventListener("click", decreaseCounter);
increaseButton.addEventListener("click", increaseCounter);

function decreaseCounter() {
  counterValue--;
  counterDisplayElement.innerHTML = counterValue;
}

function increaseCounter() {
  counterValue++;
  counterDisplayElement.innerHTML = counterValue;
}

When we first learn JavaScript we see code like this ☝️

YUCK! 🤮

<body>
  <Counter />
</body>
const Counter = () => {
  const [counter, setCounter] = useState(0);

  return (
    <div>
      <p>
        The counter is <span> {counter} </span>
      </p>
      <button type="button" onClick={() => setCounter(counter - 1)}>
        Decrease
      </button>
      <button type="button" onClick={() => setCounter(counter + 1)}>
        Increase
      </button>
    </div>
  );
};

But in actual apps, we'd write something like this. Simpler, declarative API which increases productivity!

This why frameworks/libraries

are always used.

✔️ The most popular one is React  but here Squoosh uses Preact, a much much lighter alternative.

CODECS

AVIF

MozJPEG

WebP

...

WEB
WORKER
SERVICE
WORKER
CANVAS
PREACT
CLIENT

WASM

ROLLUP

✔️ Apps use bundlers to increase app performance, create a better dev experience and extend with features not natively supported.

Rollup is a module bundler for JavaScript.

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static distance(a, b) {
    const dx = a.x - b.x;
    const dy = a.y - b.y;

    return Math.hypot(dx, dy);
  }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

console.log(Point.displayName); 
console.log(Point.distance(p1, p2));
class Point{constructor(t,n){this.x=t,this.y=n}static distance(t,n){const o=t.x-n.x,s=t.y-n.y;return Math.hypot(o,s)}}const p1=new Point(5,5),p2=new Point(10,10);console.log(Point.distance(p1,p2));

We code like this

But why not ship like this ???

370 bytes
VS
198 bytes

Performance

<head>
  <title> App </title>
  <script 
    src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
  <script 
    src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
  <script 
    src="https://raw.githubusercontent.com/lodash/lodash/4.17.15-npm/lodash.js"></script>
  <!-- .... -->
</head>
<body>

  <script>
    // window.moment
    // window.sweetAlert
    // window.lodash
  </script>
</body>
import Swal from 'sweetalert2';
import lodash from 'lodash';
import moment from 'moment';

// Then use as variables, not from Window

Dev Experience

Instead of importing via CDN

Use NPM packages and import where needed

New features

const Counter = () => {
  const [counter, setCounter] = useState(0);

  return (
    <div>
      <p>
        The counter is <span> {counter} </span>
      </p>
      <button type="button" onClick={() => setCounter(counter - 1)}>
        Decrease
      </button>
      <button type="button" onClick={() => setCounter(counter + 1)}>
        Increase
      </button>
    </div>
  );
};
const Counter = () => {
  const [counter, setCounter] = useState(0);

  return React.createElement(
    "div",
    null,
    React.createElement(
      "p",
      null,
      "The counter is ",
      React.createElement(
        "span",
        null,
        " ",
        counter,
        " "
      )
    ),
    React.createElement(
      "button",
      { type: "button", onClick: () => setCounter(counter - 1) },
      "Decrease"
    ),
    React.createElement(
      "button",
      { type: "button", onClick: () => setCounter(counter + 1) },
      "Increase"
    )
  );
};

Use features not natively supported, like JSX

But convert to actual JS when shipping the code

✔️ Cannot think of a single non-trivial app that's not using a bundler. They literally are used EVERYWHERE!

CODECS

AVIF

MozJPEG

WebP

...

WEB
WORKER
SERVICE
WORKER
CANVAS
PREACT
CLIENT

WASM

ROLLUP

A worker with special powers. Unlike usual Web Workers this one runs in the background even if the app is closed.

✔️ Allows offline experiences, push notifications and app installations.

📁 index.html
📁 style.css
📁 ...
Server
📁 index.html
📁 style.css
📁 ...
squoosh.app

Offline

// Main App
navigator
  .serviceWorker
  .register("service-worker.js")
  .then(swRegistration => { 
    console.log("Service worker succesfully registered!");
  }, err => {
    console.error(`SW installation failed: ${err}`);
  });
// Service Worker
const VERSION = 1;
const CACHE_NAME = `cache-${VERSION}`;

const resourcesToCache = [
  "index.html",
  "src/bundle.js",
  "src/styles/style.css"
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      return cache.addAll(resourcesToCache)
    })
  );
});

self.addEventListener('fetch', event => {
  if (event.request.url.indexOf(location.origin) === 0) {
    const duplicatedRequest = event.request.clone();

    event.respondWith(caches.match(event.request).then(resp => {
      return resp || fetch(duplicatedRequest);
    }));
  }
});

App Installation

✔️ Squoosh.app uses a Service Worker to work offline, and be able to install on your device.

CODECS

AVIF

MozJPEG

WebP

...

WEB
WORKER
SERVICE
WORKER
CANVAS
PREACT
CLIENT
ROLLUP

WASM

so... is FrontEnd is just buttons?

👀

This app seems to be just one big button, so... yeah 😅

Thank you! 🙏