Things NOT to expect
- Blueprint for PWA
development
- No AuthN/AuthZ
Things To Expect
- Extensive/up-to-date insights
into PWA and Project Fugu
- A productivity app use case
that works on your desktop &
smartphone
- Lots of fun
- Hands-on exercises
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Angular meets Project Fugu
Slide 5
Slide 5 text
https://paint.js.org
– Productivity app
– Draw images
– Lots of actions & tools
– Installable
– Read/save files
– Copy/paste images
from/to clipboard
– Share files to other apps
– Register for file extensions
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Demo Use Case
Slide 6
Slide 6 text
(Workshop Edition)
– Productivity app
– Draw images
– Lots of actions & tools
– Installable
– Read/save files
– Copy/paste images
from/to clipboard
– Share files to other apps
– Register for file extensions
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Demo Use Case
Slide 7
Slide 7 text
Setup complete?
(Node.js, Google Chrome, Editor, Git)
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Setup (1/3)
LAB #0
Slide 8
Slide 8 text
git clone https://github.com/thinktecture/
angular-days-spring-2023-fugu.git
cd angular-days-spring-2023-fugu
npm i
npm start -- --open
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Setup (3/3)
LAB #0
Canvas
– Plain bitmap for the web
– Cross-platform, hardware-
accelerated graphics
operations
– Supports different contexts
(2D, 3D: WebGL, WebGL 2.0)
– Supported on all evergreen
browsers and on IE 9+
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint
Slide 12
Slide 12 text
Canvas
Add a canvas element to app.component.html:
Query the canvas element in app.component.ts:
@ViewChild('canvas') canvas?: ElementRef;
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint
LAB #1
Slide 13
Slide 13 text
Canvas 2D Context
fillRect(x, y, width, height)
strokeRect(x, y, width, height)
beginPath()
moveTo(x, y)
lineTo(x, y)
fill()
stroke()
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint
Slide 14
Slide 14 text
Canvas 2D Context
1. Introduce a new field at the top of
app.component.ts:
context?: CanvasRenderingContext2D;
2. Get the 2D context in ngAfterViewInit():
const canvas =
this.canvas!.nativeElement;
const ctx = canvas.getContext('2d')!;
this.context = ctx;
3. Prepare the canvas:
ctx.fillStyle = 'white';
ctx.fillRect(0, 0,
canvas.width,
canvas.height);
ctx.fillStyle = 'black';
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint LAB #2
Slide 15
Slide 15 text
Low-latency Rendering
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint
Web pages need to synchronize
with the DOM on graphics updates
causing latencies that can make
drawing difficult
Low-latency rendering skips
syncing with the DOM with can lead
to a more natural experience
Supported on Chrome (Chrome OS
and Windows only)
Pointer Events
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint
Users nowadays use different
input methods, cross-platform
apps should cover all of them
Pointer Events offer an
abstract interface to catch all
input methods (pointerdown,
pointermove, pointerup)
event.offsetX/event.offsetY
contain the pointer’s position
relative to the listener
Slide 18
Slide 18 text
Pointer Events
1. In app.component.html, add event bindings for the pointer events:
2. In app.component.ts (onPointerMove()), draw the user input:
this.context!.fillRect(event.offsetX, event.offsetY, 2, 2);
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint LAB #4
Slide 19
Slide 19 text
Bresenham Line Algorithm
The user may move faster than
the input can be processed
For this case, we need to
remember the previous point
and interpolate the points in
between
The Bresenham line algorithm
calculates the missing pixels
between two given points
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint
Slide 20
Slide 20 text
Bresenham Line Algorithm
1. At the top of app.component.ts, a field called previousPoint to store
the previous point:
previousPoint?: { x: number, y: number };
2. In onPointerDown(), set the current point as the previous point:
this.previousPoint = { x: event.offsetX, y: event.offsetY };
3. In onPointerUp(), set this.previousPoint to undefined.
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint LAB #5
Slide 21
Slide 21 text
Bresenham Line Algorithm
4. In onPointerMove(), call the Bresenham line algorithm with the points:
if (this.previousPoint) {
const currentPoint = { x: event.offsetX, y: event.offsetY };
for (const point of
this.paintService.bresenhamLine(this.previousPoint,
currentPoint)) {
this.context!.fillRect(point.x, point.y, 2, 2);
}
this.previousPoint = currentPoint;
}
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint LAB #5
Slide 22
Slide 22 text
Color Selection
For this demo, we will only
implement the brush tool. However,
we want to bring in some color.
A simple method to implement a
color selection is to use the HTML
color-type input element that
shows the native color picker:
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint
Slide 23
Slide 23 text
Color Selection
1. In app.component.html, replace the content of the node with:
2. In app.component.ts (onColorChange()), update the context’s fill style
accordingly:
this.context!.fillStyle = color.value;
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Paint
LAB #6
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Web App
Manifest
Service
Worker
Slide 27
Slide 27 text
Web App Manifest
Distinguishes Web Apps from
Websites
JSON-based file containing
metadata for apps only
Apps can be identified by search
engines, app store providers, etc.
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Manifest Icon Purposes
(any)
any context (e.g. app icon)
monochrome
different color requirements
(at risk)
maskable
user agent masks icon as required
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Safe Zone
Windows iOS Android
Slide 31
Slide 31 text
Web App Manifest
1. Stop the npm start command, then run the following command to
add PWA support to the current project:
npm run ng add @angular/pwa
2. In manifest.webmanifest,
a) set name and short_name to values of your choice
b) change the theme_color to #000080
c) change the background_color to #808080
3. In index.html, change the theme-color to #000080.
4. Test manifest in DevTools: F12 > Application > Manifest
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA LAB #7
Slide 32
Slide 32 text
Manifest Shortcuts
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Secondary entrypoints for your
application (e.g., home screen
quick actions, jump lists, …)
Static definition in Web App
Manifest
Dynamic API may follow in the
future
Supported by Google Chrome
for Android, macOS and
Windows
Slide 33
Slide 33 text
Web App Manifest
1. In manifest.webmanifest, add (at least) the following shortcut:
"shortcuts": [{
"name": "About Paint",
"short_name": "About",
"description": "Show information about Paint",
"url": "./",
"icons": [{ "src": "assets/icons/icon-512x512.png", "sizes": "512x512" }]
}]
2. Test in DevTools: F12 > Application > Manifest
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
LAB #8
Slide 34
Slide 34 text
Web App Manifest – Chrome Install Criteria
1. Web App is not already installed
2. Meets a user engagement heuristic (user has interacted and clicked
with origin for at least 30 seconds)
3. Includes a Web App Manifest that has short_name or name, at least a
192px and 512px icon, a start_url and a display mode of
fullscreen, standalone or minimal-ui
4. Served over HTTPS
5. Has a registered service worker with a fetch event handler (subject
to change!)
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
https://web.dev/install-criteria/
Slide 35
Slide 35 text
Service Worker
JavaScript executed in an own
thread, registered by the website
Acts as a controller, proxy, or
interceptor
Has a cache to store responses (for
offline availability and performance)
Can wake up even when the website
is closed and perform background
tasks (e.g., push notifications or sync)
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Slide 36
Slide 36 text
Service Worker
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Service
Worker
Internet
Website
HTML/JS
Cache
fetch
Slide 37
Slide 37 text
NgServiceWorker
Angular CLI supports Service
Worker generation by simply
adding PWA support:
ng add @angular/pwa
One-size-fits-all Service
Worker
Pre-defined functionality,
limited customizability
PWA
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Angular meets Project Fugu
Slide 38
Slide 38 text
Workbox
Toolchain by Google
Includes a CLI
Generates a service worker
implementation from directory
contents (e.g., build output, or
our development directory)
Allows you to modify the
service worker behavior
(maximum flexibility)
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Slide 39
Slide 39 text
Service Worker
1. In your console, run: npm run pwa
2. Test in DevTools: F12 > Application > Service Worker
3. Install the app: Address Bar > Install
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
LAB #9
Slide 40
Slide 40 text
Push Notifications
Just as native apps, PWAs can
receive push notifications
Combination of two technologies:
Web Notifications and Push API
Supported by Chrome, Edge,
Firefox, Safari (on macOS)
Support coming to iOS and
iPadOS in version 16.4
(currently a RC)
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Slide 41
Slide 41 text
Service Worker Debugging
More information on installed
service workers can be found on
• about://serviceworker-
internals (Chromium-based
browsers)
• about:serviceworkers
(Mozilla Firefox)
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Slide 42
Slide 42 text
Service Worker Debugging
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Slide 43
Slide 43 text
Lighthouse
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
Auditing tool by Google,
integrated in Chrome DevTools
Automatically checks
performance metrics, PWA
support, accessibility, SEO and
other best practices and gives
tips on how to improve
Can simulate mobile devices
Slide 44
Slide 44 text
Lighthouse
1. Make sure only one tab/window of your PWA is open
2. Open DevTools: F12 > Lighthouse
3. Make sure to select at least the “Progressive Web App” category
4. Click “Analyze page load”
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
PWA
LAB #10
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Slide 47
Slide 47 text
Project Fugu
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
»Let’s bring the web
back – API by API«
Thomas Steiner, Google
Slide 48
Slide 48 text
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
Contacts
Picker
Screen Wake
Lock API
File System
Access API
Shape
Detection API
Slide 49
Slide 49 text
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
https://goo.gle/fugu-api-tracker
File System Access API
Some applications heavily rely
on working with files (e.g.
Visual Studio Code, Adobe
Photoshop, …)
File System Access API allows
you to open, save and override
files and directories
Supported by Chrome, Edge
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
Slide 52
Slide 52 text
File System Access API
1. Add the following buttons to the bar in app.component.html
(before the color input):
Open
Save
Copy
Paste
Share
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #11
Slide 53
Slide 53 text
File System Access API
2. Add the following lines at the top of app.component.ts:
readonly fileOptions = {
types: [{
description: 'PNG files',
accept: {'image/png': ['.png']}
}]
};
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #11
Slide 54
Slide 54 text
File System Access API
3. Add the following lines to the save() function:
const blob = await
this.paintService.toBlob(this.canvas!.nativeElement);
const handle = await
window.showSaveFilePicker(this.fileOptions);
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #11
Slide 55
Slide 55 text
File System Access API
Add the following code to the open() function:
const [handle] = await
window.showOpenFilePicker(this.fileOptions);
const file = await handle.getFile();
const image = await this.paintService.getImage(file);
this.context!.drawImage(image, 0, 0);
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #12
Slide 56
Slide 56 text
Async Clipboard API
Allows reading from/writing to
the clipboard in an
asynchronous manner (UI won’t
freeze during long-running
operations)
Reading from the clipboard
requires user consent first
(privacy!)
Supported by Chrome, Edge
and Safari and Firefox (plain-
text only)
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
Slide 57
Slide 57 text
Async Clipboard API
Add the following code to the copy() function:
await navigator.clipboard.write([
new ClipboardItem({ "image/png":
this.paintService.toBlob(this.canvas!.nativeElement) }),
]);
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #13
Slide 58
Slide 58 text
Async Clipboard API
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
for (const type of clipboardItem.types) {
if (type === 'image/png') {
const blob = await clipboardItem.getType(type);
const image = await this.paintService.getImage(blob);
this.context!.drawImage(image, 0, 0);
}
}
}
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #14
Slide 59
Slide 59 text
Web Share API
Allows sharing a title, URL, text, or
files
API can only be invoked as a
result of a user action (i.e. a click
or keypress)
Supported by Chrome, Edge,
Safari and Firefox (Android only)
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
Slide 60
Slide 60 text
Web Share API
const blob = await
this.paintService.toBlob(this.canvas!.nativeElement);
const file = new File([blob], 'untitled.png', {type:
'image/png'});
const item = { files: [file], text: 'Awesome drawing' };
if (navigator.canShare(item)) {
await navigator.share(item);
}
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #15
Slide 61
Slide 61 text
File Handling API
Register your PWA as a
handler for file extensions
Requires installing the
application first
Declare supported extensions
in Web App Manifest and add
imperative code to your
application logic
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
Slide 62
Slide 62 text
File Handling API
1. Add the following property to your manifest (manifest.webmanifest):
"file_handlers": [{
"action": "/index.html",
"accept": {
"image/png": [".png"]
}
}]
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #16
Slide 63
Slide 63 text
File Handling API
2. Add the following code to ngAfterViewInit() in app.component.ts:
if ('launchQueue' in window) {
window.launchQueue.setConsumer(async params => {
const [handle] = params.files;
if (handle) {
const file = await handle.getFile();
const image = await this.paintService.getImage(file);
ctx.drawImage(image, 0, 0);
}
});
}
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #16
Slide 64
Slide 64 text
File Handling API
3. Rebuild PWA: npm run pwa
Note: Wait for a few seconds and reload the application after opening,
as the PWA needs to fetch the new files first.
about://apps
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
LAB #16
Slide 65
Slide 65 text
Summary
- Project Fugu helps the web to become more and more capable
- Project Fugu APIs could bring many more app experiences to the web
(IDEs, productivity apps, etc.)
- But: Web is threatened by alternative approaches and platforms,
support for modern Web API varies from platform to platform
- You can make a difference!
- File bugs in browser engine bugtrackers
- File Fugu requests: https://goo.gle/new-fugu-request
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Capabilities
Overview
Use available interfaces and functions of
a system (opposite of Graceful
Degradation)
Users with modern, feature-rich
browsers get a better experience
Apps are available on older browsers, but
with limited functionality
Concept: Browser feature support should
grow over time—thereby more users can
enjoy an increasing number of features
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Progressive Enhancement
Slide 68
Slide 68 text
Overview
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(…)
.then(() => /* … */);
}
In JavaScript: check whether an API/feature is available. If yes—use it!
Otherwise:
1. Disable the functionality
2. Fall back to an alternative API (if available)
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Progressive Enhancement
Slide 69
Slide 69 text
New powerful APIs regularly ship with new releases of Chromium-based
browsers
Some only add minor finishing touches, others enable whole application
categories as productivity apps to finally make the shift to the web
Some APIs already made their way into other browsers (e.g., Web Share)
Fugu process makes sure that capabilities are implemented in a secure,
privacy-preserving manner
Let’s make the web a more capable platform!
Angular meets Project Fugu
Produktivitäts-PWAs auf Desktopniveau (Hands-on)
Summary
Slide 70
Slide 70 text
Thank you
for your kind attention!
Christian Liebel
@christianliebel
[email protected]