Scalable PWA

2e0e89a34badf79dcff642cb7b5c126f?s=47 Kazunari Hara
February 01, 2020

Scalable PWA

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

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

2e0e89a34badf79dcff642cb7b5c126f?s=128

Kazunari Hara

February 01, 2020
Tweet

Transcript

  1. Feb. 1 2020, PWA Night CONFERENCE 2020 Kazunari Hara, CyberAgent

    Scalable 〜こえのブログ最新事例〜
  2. is a web app focusing on UX

  3. voice.ameba.jp voice.ameba.jp voice.ameba.jp AD Loading too slow Unexpected layout shift

    Desktop view on mobile
  4. meow にゃーん (やーん)

  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
  6. None
  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
  8. こえのブログ Posting a blog entry just by speaking • Audio

    recording • Speech-to-Text • Audio player • Installable •
  9. • Posting blog with audio and text • The editor

    is a PWA
  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);
  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();
  12. Transcoding with WASM reduces audio sizes https://github.com/Kagami/vmsg • In Web

    Worker • Execute periodically • WAV to MP3 -90% Audio sizes
  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); };
  14. Saving Draft to IndexedDB and restore it

  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
  16. Add to Home Screen as an application on OSes Criteria:

    • https • Service Worker with fetch • Web App Manifest etc...
  17. Full experiences: Works on Limited experiences:

  18. Made with

  19. Challenges for Scalable PWA

  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
  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
  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 <script type="module" src="main.esm.mjs"></script> <script nomodule src="main.es5.js"></script> ECMAScript 2016+ compatibility table is almost all green, but we need to load polyfill for now https://kangax.github.io/compat-t able/
  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/
  24. https://twitter.com/addyosmani/status/1194710153414594561 Speed Badges on Chrome (planning)

  25. Consistently Fast even during traffic spikes (13x traffic spikes occurred)

    Caches ensure site stability: • Server-side caches • Client-side caches
  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
  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
  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
  29. https://speakerdeck.com/herablog/using-cdn-to-improve-web-performance

  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
  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
  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)
  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
  34. Monitoring Perf Budget Daily basis: SpeedCurve, Lighthouse CI... (Lab) Firebase

    Perf, CrUX… (Field) Deployment basis: SpeedCurve (Lab) Before deployment: Bundle size on CI
  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
  36. Apps need to be cleaned everyday like cats

  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
  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/
  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
  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
  41. Differential Rendering for social media crowlers and browsers inc Googlebot

    Server-side meta rendering <title>${pageTitle}</title> <meta property="og:type" content="website"> <meta property="og:image" content="${image}"> <voice-app></voice-app> <script type="module" src="src/components/voice-app.js" crossorigin></script> Client-side app rendering
  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
  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
  44. Accessibility Tools checks additional accessibility issues Checking screen reader using

    VoiceOver Inspecting Accessibility Tree using DevTools Collaboration between designers and developers using VisBug
  45. Keyboard Usability screen reader usability as well Ensuring current position:

    • Displaying outlines • Controlling focuses
  46. Reduce Motions stops animations if the user prefers-reduced-motion @media (prefers-reduced-motion:

    reduce) { .item-placeholder { animation: none; } }
  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
  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
  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
  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'); };
  51. Native Lazy-loading defers the loading of off-screen elements <img alt=””

    data-src=”https://...” loading=”lazy” /> <noscript> <img alt=””src=”https://...” loading=”lazy” /> </noscript> if ('loading' in HTMLImageElement.prototype) { // copy value from data-src to src } else {} // fallback with Intersection Observer https://twitter.com/herablog/status/1164475719100952576
  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/
  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
  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 }
  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
  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
  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
  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 <input type=”file” /> to open file // use <a download> to download files } Planning
  59. Periodic Background Sync refreshes data periodically in backgound Use cases

    (planning): • updating rankings • downloading audios by favorite bloggers Planning
  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
  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; } }
  62. Project Fugu for the future web apps https://goo.gle/fugu-api-tracker

  63. Passion and Collaborations

  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