Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Scalable PWA

Scalable PWA

Scalable PWA 〜こえのブログ最新事例〜

PWA Night CONFERENCE 2020
https://conf2020.pwanight.jp/

Kazunari Hara

February 01, 2020
Tweet

More Decks by Kazunari Hara

Other Decks in Technology

Transcript

  1. Feb. 1 2020, PWA Night CONFERENCE 2020
    Kazunari Hara, CyberAgent
    Scalable
    〜こえのブログ最新事例〜

    View Slide

  2. is
    a web app
    focusing on UX

    View Slide

  3. voice.ameba.jp voice.ameba.jp voice.ameba.jp
    AD
    Loading too slow Unexpected layout shift Desktop view on mobile

    View Slide

  4. meow にゃーん (やーん)

    View Slide

  5. ● Reliable - Load instantly even when offline
    ● Fast - Respond quickly and no junk scrolling
    ● Engaging - Feel like a natural app on the device
    https://developers.google.com/web/progressive-web-apps

    View Slide

  6. View Slide

  7. ● Reliable - Load instantly even when offline
    ● Fast - Respond quickly and no junk scrolling
    ● Engaging - Feel like a natural app on the device
    ● Scalable - Being improved consistently

    View Slide

  8. こえのブログ
    Posting a blog entry just by
    speaking
    ● Audio recording
    ● Speech-to-Text
    ● Audio player
    ● Installable

    View Slide

  9. ● Posting blog with audio
    and text
    ● The editor is a PWA

    View Slide

  10. Device
    Microphone
    with
    MediaDevices.getUserMedia()
    https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
    navigator.mediaDevices.getUserMedia({
    audio:
    autoGainControl: false, channelCount: 1,
    echoCancellation: true, noiseSuppression: true,
    })
    .then(stream => // use stream);

    View Slide

  11. Getting Audio
    from Mic
    and save/post it later
    const mediaRecorder = new MediaRecorder(stream, options);
    mediaRecorder.addEventListener('stop', () => {
    const audioBlob = new Blob(recordedChunks);
    const audioUrl = URL.createObjectURL(audioBlob);
    downloadLink.href = audioUrl;
    downloadLink.download = 'audio.wav';
    });
    mediaRecorder.start();

    View Slide

  12. Transcoding
    with WASM
    reduces audio sizes
    https://github.com/Kagami/vmsg
    ● In Web Worker
    ● Execute periodically
    ● WAV to MP3
    -90%
    Audio sizes

    View Slide

  13. Speech-to-Text
    on Cloud
    converts audio to text by applying powerful neural
    network models
    const speech = require('@google-cloud/speech');
    const client = new speech.SpeechClient();
    const recognize = () => {
    const request = {
    audio: { uri: 'gs://...' },
    config: { languageCode: 'ja-JP', enableWordTimeOffsets: true },
    };
    return client.recognize(request);
    };

    View Slide

  14. Saving Draft
    to IndexedDB and restore it

    View Slide

  15. Playing Audio
    with the user’s permission
    ● Asking permission to play audio after
    prompt on the first encounter
    ● If the user says “OK”, start playing audio
    and save the status to the browser
    storage
    ● If the user says “NO”, always ask before
    playing audio

    View Slide

  16. Add to
    Home Screen
    as an application on OSes
    Criteria:
    ● https
    ● Service Worker with fetch
    ● Web App Manifest etc...

    View Slide

  17. Full experiences:
    Works on
    Limited experiences:

    View Slide

  18. Made with

    View Slide

  19. Challenges for
    Scalable PWA

    View Slide

  20. Single Origin
    with HTTPS
    helps overcome many
    challenges in PWAs
    ● Service worker scopes
    ● New feature permissions
    ● Controllable caches
    ● Reading cookies
    https://web.dev/multi-origin-pwas/
    https://voices.ameba.jp/*/
    {api, assets, images, src}
    voice.ameba.jp

    View Slide

  21. App Strategy
    at Ameba
    こえのブログ shipped as a PWA:
    ● To create experimental fetures
    ● To provide app to major OSes
    ● Not to increase native app sizes
    ● PWA already works on many
    browsers

    View Slide

  22. Including Polyfill
    to provide modern functionality on older browsers
    Some polyfill options:
    Bundle JS files with polyfills like core-js
    Using polyfill services like polyfill.io
    Differential script loading
    is also recommended


    ECMAScript 2016+ compatibility
    table is almost all green, but
    we need to load polyfill for now
    https://kangax.github.io/compat-t
    able/

    View Slide

  23. Perf is Critical
    for user experience in PWA
    ● High priority for better UX
    ● Users prefer fast apps
    ● Better for business metrics
    voice.ameba.jp
    -44%
    Client Rendering Time
    +57%
    Page Views
    https://developers.cyberagent.co.jp/blog/archives/636/

    View Slide

  24. https://twitter.com/addyosmani/status/1194710153414594561
    Speed Badges on Chrome (planning)

    View Slide

  25. Consistently
    Fast
    even during traffic spikes
    (13x traffic spikes occurred)
    Caches ensure site stability:
    ● Server-side caches
    ● Client-side caches

    View Slide

  26. CDN
    for server-side stability
    ● Long TTL (1 day by default)
    ● Event-driven cache purging
    ● Serving stale content
    98%
    Cache Hit Ratio
    99%
    Cache Coverage

    View Slide

  27. Service Worker
    for client-side caching
    ● Pre-caching app assets
    ○ updated precisely with server
    file update
    ● Runtime assets caches (except partial
    audios)
    ● HTTP caches if the browser does
    not support SW
    98%
    Cache Cavarage

    View Slide

  28. Cache Overview
    to improve site speed and consistency
    Origin Server / DB
    CDN
    Browser
    Purge on data update
    98%
    Cache Cavarage
    98%
    Cache Hit
    Fetch on file change
    High cache hit/coverage
    reduces unnecessary network
    requests

    View Slide

  29. https://speakerdeck.com/herablog/using-cdn-to-improve-web-performance

    View Slide

  30. Perf Budget
    helps ensure good user
    experience and business
    metrics
    The team need to maintain
    ● Perf budget
    ● Performance monitoring
    ● Improve decision making in
    development flow

    View Slide

  31. Lab data vs Field data
    Assessing app performance using both types of data
    Lab
    Controlled/Consistent Real-world/Wild
    Field
    Lighthouse
    DevTools
    SpeedCurve
    Chrome User Experience Report
    Firebase Performance Monitoring
    SpeedCurve

    View Slide

  32. Setting
    Perf Budget
    1. Measuring the app in lab
    2. Comparing metrics to competitors
    with 20% rule
    3. Setting perf budgets
    4. Monitoring budgets on a daily or a
    deployment basis
    5. Updating budgets (e.g. adding Field metrics)

    View Slide

  33. Perf Budget Now
    Setting aggressive budgets to find out regressions early
    FCP on Fast 3G <= 1.5s
    TTI on Fast 3G <= 3s
    Entrypoint HTML <= 14KB
    App shell JS <= 120KB
    Chunk JS <= 20KB

    View Slide

  34. Monitoring Perf Budget
    Daily basis:
    SpeedCurve, Lighthouse CI... (Lab)
    Firebase Perf, CrUX… (Field)
    Deployment basis:
    SpeedCurve (Lab)
    Before deployment:
    Bundle size on CI

    View Slide

  35. Perf Budget
    in development flow
    Some steps before consuming
    perf budget:
    ● Reducing size if possible
    ● Finding reason for size
    increases
    ● Issuing it to refactor later
    Exceeded?
    Ship it!
    Can reduce size?
    Reduce size
    Issue reason
    Consume budget
    Refactor
    Ship it!
    No
    Yes
    No
    Yes

    View Slide

  36. Apps need to be cleaned
    everyday like cats

    View Slide

  37. Continuous
    Deployment
    for site realiability
    ● Deployment is fast, easy, safe,
    and frequent
    ● Rollbacks are also easy
    ● Master branch is deployed
    automatically (on a daily basis,
    planning)
    >= 1,000
    Releases in 10 Month
    Push
    CLI
    Purge

    View Slide

  38. Tech Stack
    better performance, higher security,
    cheaper, easier scaling, and better DX
    Similar approach to JAMStack:
    ● Entire Project on a CDN
    ● Everything Lives in Git
    ● Modern Build Tools
    ● Automated Builds
    ● Atomic Deploys
    ● Instant Cache Invalidation
    Cloud
    Functions
    Cloud
    Storage
    Cloud
    Functions
    Web App Assets
    Audios
    API
    POST/DELETE
    API
    GET
    93%
    Endpoints Cacheable
    https://jamstack.org/

    View Slide

  39. Writing Tests
    ensures continuous deployment
    and app quality
    ● Logic unit testing
    ● Visual regression testing (pages)
    Tests working in progress:
    ● Logic unit testing on brosers
    ● Server-side testing
    https://qiita.com/junkisai/items/016c567a9fbade08d65b

    View Slide

  40. Traffic reffarals
    to increase visitors
    Social media
    Native Apps Search engines
    Open PWA from native apps
    Primary pages are on
    ameblo.jp not voice.ameba.jp

    View Slide

  41. Differential Rendering
    for social media crowlers and browsers inc Googlebot
    Server-side meta rendering
    ${pageTitle}



    src="src/components/voice-app.js"
    crossorigin>
    Client-side app rendering

    View Slide

  42. Image CDN
    creates eyecatch images
    displayed in social media
    ● Inserting landmark
    ● Cropping, resizing
    ● Converting appropriate
    format
    /image.jpg?
    crop=1200:630&width=1200&overlay=share

    View Slide

  43. Accessibility
    improves user experience
    ● Color contrast
    ● Machine readability
    ● Keyboard usability
    ● User preferences etc...
    voice.ameba.jp
    Only a subset of
    accessibility issues can be
    automatically detected

    View Slide

  44. Accessibility Tools
    checks additional accessibility issues
    Checking screen reader
    using VoiceOver
    Inspecting Accessibility
    Tree using DevTools
    Collaboration between
    designers and developers
    using VisBug

    View Slide

  45. Keyboard Usability
    screen reader usability
    as well
    Ensuring current position:
    ● Displaying outlines
    ● Controlling focuses

    View Slide

  46. Reduce
    Motions
    stops animations if the user
    prefers-reduced-motion
    @media (prefers-reduced-motion: reduce) {
    .item-placeholder {
    animation: none;
    }
    }

    View Slide

  47. Dark Mode
    respects prefers-color-scheme
    Applied with CSS custom
    properties
    @media (prefers-color-scheme: dark) {
    :root {
    --app-background-color: black;
    --app-text-color: white;
    }
    }
    Planning

    View Slide

  48. Accessibility
    Guidelines
    explains how can we improve
    user experience
    ● Based on WCAG 2.1
    ● Web Bundle is available
    https://openameba.github.io/a11y-guidelines/
    openameba.github.io
    https://github.com/openameba/a11y-guidelines/releases

    View Slide

  49. Progressive
    Enhancement
    to provide first-class
    experiences to the user
    Not only for visual designs:
    ● Feature detections
    ● Polyfill or other solutions
    voice.ameba.jp
    voice.ameba.jp

    View Slide

  50. Permissions API
    Not available:
    Always asking the permission
    Available:
    Checking the permission
    before recording
    const checkMicPermission = async () => {
    const permissionStatus =
    await navigator.permissions.query({
    name: 'microphone',
    });
    if (permissionStatus.state === 'denied') {
    // Display dialog...
    } else {
    // Start recording...
    }
    // You can also use addEventListener
    //
    permissionStatus.addEventListener('change');
    };

    View Slide

  51. Native
    Lazy-loading
    defers the loading of off-screen
    elements




    if ('loading' in HTMLImageElement.prototype) {
    // copy value from data-src to src
    } else {} // fallback with Intersection Observer
    https://twitter.com/herablog/status/1164475719100952576

    View Slide

  52. Is Native Lazy-loading
    too eager?
    If it is true for your app, you can
    load images with
    ● Intersection Observer
    ● Element Lazy-rendering
    https://calendar.perfplanet.com/2019/native-image-lazy-loading-in-chrome-is-way-too-eager/

    View Slide

  53. Web Share
    invokes the native sharing
    mechanism of the device
    The apps or the person could be
    suggested based on the user’s
    engagement

    View Slide

  54. Web Share
    invokes the native sharing
    mechanism of the device
    if ('share' in navigator) { // Chrome, Safari
    navigator.share({ title: '', text: '', url: '' });
    } else {
    // Display custom dialog
    }

    View Slide

  55. Wake Lock
    prevents devices from dimming
    while recording
    The users can
    ● check the remaining time
    ● tap the stop button
    ● remove noises of when the
    device starts recording in
    background
    O
    rigin
    Trial

    View Slide

  56. Wake Lock
    prevents devices from dimming
    while recording
    if ('wakeLock' in navigator) { // Chrome
    let wakeLock;
    const requestWakeLock = async () => {
    try {
    wakeLock
    = await navigator.wakeLock.request('screen');
    } catch (err) { console.error(err); }
    };
    document.addEventListener('visibilitychange', handler);
    document.addEventListener('fullscreenchange', handler);
    } else {
    // you can use NoSleep.js if wake lock is a critical fearture
    // no fallback also makes sence
    }
    O
    rigin
    Trial

    View Slide

  57. Native File
    System
    enables developers to control
    device storage
    Use cases (planning):
    ● opening files in the storage
    ● saving recorded audios
    ● downloading favorite audios
    Planning

    View Slide

  58. Native File
    System
    enables developers to control
    device storage
    // Chrome
    if (‘chooseFileSystemEntries’ in window) {
    const fileHandle =
    await window.chooseFileSystemEntries();
    } else {
    // fallback with HTML element
    // use to open file
    // use to download files
    }
    Planning

    View Slide

  59. Periodic
    Background Sync
    refreshes data periodically in
    backgound
    Use cases (planning):
    ● updating rankings
    ● downloading audios by
    favorite bloggers
    Planning

    View Slide

  60. Periodic
    Background Sync
    refreshes data periodically in
    backgound
    const registration
    = await navigator.serviceWorker.ready;
    if ('periodicSync' in registration) { // Chrome
    await registration.periodicSync.register(
    'content-sync',
    { minInterval: 24 * 60 * 60 * 1000 } // one day
    );
    }
    Planning

    View Slide

  61. UA Client Hints
    simplify User Agent string
    HTTP request header , User-Agent,
    is going to be freezed
    Tested in Google Chrome Canary 81
    if (req.http.Sec-CH-UA ~ "Google Chrome (\d+)$")
    if (std.atoi(re.group.1) >= 63) {
    call esm_origin;
    }
    }

    View Slide

  62. Project Fugu
    for the future web apps
    https://goo.gle/fugu-api-tracker

    View Slide

  63. Passion and
    Collaborations

    View Slide

  64. @herablog
    Related documents:
    ● アメブロ2019: こえのブログでのPWA
    https://developers.cyberagent.co.jp/blog/archives/20506/
    ● Web App Checklist 〜高品質のWebアプリケーションをつくる
    ために〜
    https://speakerdeck.com/herablog/web-app-checklist-2019-at-inside-frontend
    ● こえのブログでのPWA ~ PWA編 ~
    https://speakerdeck.com/herablog/pwa-night-vol-dot-4
    ● こえのブログでのPWA ~ 開発現場編 ~
    https://speakerdeck.com/herablog/koe-no-blog-pwa
    ● 最新CDN入門 WEB+DB PRESS Vol.109
    https://gihyo.jp/magazine/wdpress/archive/2019/vol109
    ● CDNフル活用でつくる高速 Webアプリ
    https://speakerdeck.com/herablog/using-cdn-to-improve-web-performance
    Life
    Have a nice

    View Slide