Intro to Qwik

The Answer to Web App Scalability Issues

Doguhan Uluca

Principal Fellow  at

@duluca

Modern Software Delivery

Have you had performance issues with your web app?

  • First Contentful Paint
  • Time to Interactive
  • Latency
  • Frame drops
  • Others?

Performance Indicators

The browser is a complicated runtime environment

The frameworks we use obfuscate the runtime in exchange for rich features and easier to maintain code

Frameworks of 2023 are really complicated in their own right

Credit Michael Hladky

Profiling Angular

Credit Michael Hladky

Profiling Angular

  • Downloading the JavaScript
    • App Code (Framework + 3rd party libraries)
  • Executing the JavaScript
    • Loading, JITing, and scaffolding all the code
  • Hydrating App Code
    • Compute the state, connect listeners to DOM, render
  • Change detection
    • Complicated component trees
  • Others?

What's Slowing Us Down?

Created by Miško Hevery @mhevery

Supported by Builder.io

Adam Bradley @adamdbradley

Manu Corporat @manucorporat

5-10x faster websites

Full page load under 1 second, at scale

Easy to adopt (use 1 command/click)

Intro to Qwik

  1. The Need for Qwik
  2. Resumability
  3. Qwik Components
  4. Reactivity
  5. Tips for Starting with Qwik

The Need for Qwik

1

What's the fastest way to render a web page?

Possible Solutions

  1. Reduce use of 3rd party code
  2. Ahead of Time Compilation and code splitting
  3. Lazy load modules
  4. Server-side rendering
  5. Optimize each component by hand
  6. Remove features from your app
  7. Ditch JavaScript and deliver pure HTML

Credit Cube Drone

Become

a minimalist

Qwik is a Minimalist

  • Tiny 1 KB framework
  • Aggressively delays download and execution of JS
  • Doesn't need to hydrate to start

Sandbags of Complexity

We Want Great DX

Qwik is Simple

  • No clever algo doing magic
  • Allows you to create reusable, resumable components
  • Familiar syntax to React

component$()

export const HelloWorld = component$(() => {
  return <div>Hello world</div>;
});
export const Button = component$(() => {
  return <button onClick$={() => console.log('click')}>Click me</button>;
});
export const LocalStateExample = component$(() => {
  const state = useSignal({
    value: 0,
  });
  return <div>Value is: {state.value}</div>;
});

Server-Side Rendering (SSR) is expensive

Engineers are expensive

Experts are even more expensive

Qwik makes SSR easy

  • Resumable from a SSR rendered state
  • Components can be serialized, thus resumable
  • Progressive: Optimizer allows for fine grading lazy loading

Resumability

2

Hydration 

Hydration

Ready

Ready

Resumable

Bind listeners

Parse & execute JS

Download all page JS

Get HTML

Get HTML

Angular

app.ts

rootRouter

services

pipes

modules

/a: default

/master

/detail

/b/...

/c

childRouter

/d

/e

/f

React

App.js

Presentational

Container

Provider

Router

Component Legend

react-router

react-redux

Hydration 

  • Framework state
    • Framework internals
    • Component trees
    • Listeners
  • App state
    • Parent component dependencies
    • User data

Hydration 

  • Expensive
  • Pure overhead
  • A fundamental architectural dependency

Resumability

  • Seamlessly continue from SSR output
  • Enable async lazy loading
  • O(∞) → O(1)
  1. Efficiently deal with listeners
  2. Be able to independently restore components

Goals:

Solutions:

Listeners

Express listeners such that browser doesn't need to

eagerly load and process all listeners and event handlers

<button on:click="./chunk.js#handler_symbol">click me</button>

QRL (Qwik URL) points to a JS chunk to be lazily executed

Serialization

Isolate dependencies, then serialize state into HTML

JSON.stringify(component)

Serialization

Qwik can serialize components and static/reactive state

Serializable

  • Circular references

  • DOM references

  • Promises

  • Function closures
    (if wrapped in QRL)

  • Dates

  • URL objects

  • Map and Set instances

Not serializable

  • Classes
    (instanceof and prototype)

  • Streams

Resumability

Qwik enforces scalable patterns

Developers don't need a crystal ball to optimize the application

Qwik Components

3

A Qwik Component

useSignal() or useStore() allows reactive state management

import { component$, useStore } from '@builder.io/qwik';

export const MyCmp = component$((props: MyCmpProps) => {
  const count = useSignal(0);

  return (
    <>
      <span>
        Hello, {props.name} {count.value}
      </span>
      <div>Times: {count.value}</div>
      <button
        onClick$={() => {
          count.value++;
        }}
      >
        Increment
      </button>
    </>
  );
});

Component "Tree"

Components can use other components and pass values 

export const Counter = component$((props: {step?:number, initial?: number}) => {
  ...
});

export const MyApp = component$(() => {
  return (
    <>
      <div>Single: <Counter /></div>
      <div>Dozens: <Counter step={12}/></div>
    </>
  );
});

How Component Isolation Works

Simple Parent-Child Relationship

export const Child = () => <span>child</span>;

const Parent = () => (
  <section>
    <Child />
  </section>
);
export const Child = component$(() => {
  return <span>child</span>;
});

export const Parent = component$(() => {
  return (
    <section>
      <Child />
    </section>
  );
});

Wrap with component$()

Lazy Loading

Optimizer transformation

const Child = componentQrl(qrl('./chunk-a', 'Child_onMount'));
const Parent = componentQrl(qrl('./chunk-b', 'Parent_onMount'));
const Parent_onMount = () => qrl('./chunk-c', 'Parent_onRender');
const Parent_onRender = () => (
  <section>
    <Child />
  </section>
);
<div>
  <section>
    <div></div>
  </section>
</div>

onRender

🦥

Buffering

  • Latency 
  • Non-linear
  1. Pre-fetching
  2. Multi-threading
  3. Qwik City (Router): Speculative fetching, reducing network waterfalls

Issues:

Solutions:

Component API

  • State
    • Static and Reactive
  • Events
    • Element, Window, or Document
  • Lifecycle Hooks
    • Task, Render, VisibleTask
  • Context
    • Shared state
  • Resource
    • Wrapper for asynchronously computed values

Component API

  • Slots
    • Content projection 
  • Rendering
    • Out-of-order and asynchronously 
  • Styling
    • Per component, scoped, global
  • Lite components 

Qwik Components

  • Isolated
  • Lazy loaded
  • Reactive

Reactivity

4

 Have you ever profiled

frame drops? 

Credit Michael Hladky

Change detection

Adapted from Michael Hladky

Change detection

zone

.js

TICK

UPDATE

_

Idling

Dirty marking

Rendering

Adapted from Michael Hladky

OnPush

Idling

Dirty marking

Rendering

Adapted from Michael Hladky

Using rxAngular's directives or pipes

Idling

Dirty marking

Rendering

_

Credit Michael Hladky

Assisting Change detection

Deep Expertise

Reactivity

  • Tracks which components are subscribed to a state
  • Invalidates only the relevant component on state change
  • Initial state is computed on the server, so browser doesn't need to re-render
  • No hydration means no need to re-build reactivity graph
  • Uses proxies for change detection (over zone.js or Virtual DOM)

Proxies

Keeps track of subscription automatically

export const ComplexCounter = component$(() => {
  const state = useSignal({ count: 0, visible: true });

  return (
    <>
      <button onClick$={() => (state.visible = !state.visible)}>
        {state.visible ? 'hide' : 'show'}
      </button>
      <button onClick$={() => state.count++}>increment</button>
      {state.visible ? <span>{state.count}</span> : null}
    </>
  );

Can always compute the smallest set of invalidated components

Proxies

  • Proxies also work on deep objects
  • Child components can be invalidated in a similar fashion

Reactivity

Reactivity enables best possible rendering performance

App performance doesn't suffer as the application grows in complexity

Tips for Starting with Qwik

 

5

Partytown

Existing Codebases

  • Consider rebuilding your landing page with Qwik
  • Use Partytown to move all third-party scripts to web worker
  • Leverage Partytown integrations for React, Angular, Vue, Next.js and more

Resources

Qwik in 6 points

  1. Brings the developer closer to the metal, the DOM
  2. Qwik components are resumable and independent
  3. Surgically loads only the required bits of JS
  4. ... and does all that asynchronously
  5. ... and leverages web workers to free up the main thread
  6. Components only trigger re-render, when there's a state change

Qwik

is a minimalist

We're hiring, including fully remote positions!

Intro to Qwik: The Answer to Web App Scalability Issues

By Doguhan Uluca

Intro to Qwik: The Answer to Web App Scalability Issues

At scale everything breaks. All the Angular and React in the world can't help, when even laws of physics break down at different scales. Qwik is an upcoming new framework to build web applications with O(1) scalability. It forgoes hydration in of favor resumability and embraces server-side-rendering in a seamless/magical way. Qwik has plans to implement React and Angular integrations in the future, so this is definitely a framework to watch and experiment with.

  • 1,103