面白Web API 100連発
エンジニアお茶会 2020/08/19 pastak.icon @pastak
この発表のゴール
現代のウェブブラウザの目指している方向性について紹介する
モダンブラウザで使える最新の面白便利APIを紹介する
ちゃんと仕様に入りそうなもの(Googleの力技で…も含む)
(前半の各ベンダの話はpastak.icon個人の見解を含みます)
次ではない
フロントエンドなんでも相談室
前提知識のコーナー
"WebAPI"とは何を指すのか、標準化について
ECMAScript
Ecma InternationalにてECMA-262という規格番号
ほぼLiving Standardという雰囲気もあるけど、年に1回タグが付く
ES2020: ECMAScript® 2020 Language Specification
最新の様子: https://tc39.es/ecma262/
Array、Number、ES modules、async-await、class、globalThis等々JS自体の言語機能の仕様はここにある
HTML/DOM/CSS
今はwhatwgのLiving Standardなものが標準仕様
W3CはHTMLやDOMの標準策定を取りやめている
JavaScriptに含まれていないFetchやStorage、WebRTCやその他諸々はこっちで策定
FetchはAbort出来るが、PromiseはAbort出来ないのはAbortはFetchの仕様だから
DOM側のPromiseに入れようとしてたが、ESと乖離するので回避された結果
2020年春の概観 2020/05 W3C 活動概要 (日本語版)
WICG
https://wicg.io/
Web Incubator Community Group
W3C内のコミュニティグループの1つ
Web標準に新しいAPIを取り入れるための議論、仕様提案から普及の支援を目的にしたコミュニティ
現在のChromeで使える先進的な多くのAPIはここで議論され草案が作成されている段階のものが多い
2020/8/17現在約140のテーマがある
https://gyazo.com/418ba9ccc441284d55b20f6909a71930 https://wicg.io/
Webブラウザが内包しているHTMLエンジンやJavaScriptエンジンはそれぞれこれらの仕様を基に機能を実装している
V8に実装されたESの機能はnodeでも当然使える
一方で、commonjsのrequireはESで標準化されたりはしなかったし、今ブラウザに載っているStreamsの仕様はwhatwgにある(つまりnodeとは異なる)
現在のWebまたはウェブブラウザの立ち位置について
モダンなウェブブラウザ
ES modulesサポート
ネイティブ async-await
Fetch / ServiceWorker
LocalStorage / IndexedDB
WebRTC
...etc
Web by Google (TM)
Changing World, Changing Mozilla - The Mozilla Blog
Appleは正直よく分からないが、あんまりやる気は無さそう
AppStore経済圏
ServiceWorker / PWAへの追随の遅さ
一方でESには積極的に見える
いくつかのAPIのSafariへの搭載は拒否している(後述)
Chrome (/w MSEdge) が結果的にWebが持つ機能と仕様、その実装を牛耳っている
WICGで提案されているものの多くがChromiumチームからの提案でChromiumには載っていて、Origin Trialなどでフィールドレビューされているものが多くある
Introduction to Feature Policy  |  Web  |  Google Developers
Origin Trials - The Chromium Projects
それらはWebを勿論快適にするだろうとは思うものの、Chromiumの先進的なプロセス分離とサンドボックスを利用したPortalsなど他のブラウザが本当に追随できるのかという点で懐疑的でもある
WEB の自重 - ebiken
実際この資料で紹介する最新のAPIも全てChromeに載っているものである…
ううううう
(Googleが)目指している方向性
ServiceWorkerやPWA周辺などを筆頭にネイティブアプリケーションが持っていた機能をWebに持ち込む
そのための強力なセキュリティ機構やサンドボックス
Site Isolation 及び Web のセキュリティモデルの更新 | blog.jxck.io
WebAuthn / Web Payments / WebRTC / PWA Icon Shortcuts / Periodic Background Sync
Portals
モバイルを念頭に置いたウェブサイト表示の最適化
Web VitalsやPerformance計測のためのAPI
AMP / ServiceWorker / prefetch / WebBundle
Webbundle によるサブリソース取得の最適化 | blog.jxck.io
低レイヤー化
WASM / WebTransport / WebGL(Canvas)
WebUSB / Web NFC / Web Bluetooth
この辺はAppleもMozillaも懐疑的なので多分Chromeだけやり続けそう
Native File System API
コラム: プライバシーとトラッキング
AppleとMozillaはユーザートラッキングの拒否/プライバシー保護に積極的
Safari: ITP / Storageの7日間キャップ
Firefox: ETP (ITPのFx版。ブラックリストに載っているドメインからはUAが取れない等)
Googleはアドセンスやアナリティクスとの上手い兼ね合いを成立させたそう
Cookieの代替を探す方向がありつつも足並みは揃ってない
GDPRのような法律サイドからの圧力もある
3rd Party Cookieの締め出し
Safariは3rd をParty Cookie保存しない
SameSite Cookieの導入
SameSite cookies explained
Storage Access API
Storage access policy: Block cookies from trackers - Mozilla | MDN
Chromiumにも入っていて、Edgeでは有効になっている。Chromiumでは無効になっている。 https://bugs.chromium.org/p/chromium/issues/detail?id=989663#c17
chrome://flags/#storage-access-api
3rd Partry Cookieに代わる取り組み
Privacy Preserving Ad Click Attribution For the Web | WebKit
Digging into the Privacy Sandbox
cf: 最新のブラウザで変わるCookieの取り扱いやPrivacyの考え方 - Speaker Deck
フィンガープリントに利用できる懸念があるためにAppleが拒否しているWeb API達
Web Bluetooth
Web MIDI API
Magnetometer API
Web NFC API
Device Memory API
Network Information API
Battery Status API
Web Bluetooth Scanning
Ambient Light Sensor
HDCP Policy Check extension for EME
Proximity Sensor
WebHID
Serial API
Web USB
Geolocation Sensor
User Idle Detection
本題に入ります
実際にNotaで使えそうなブラウザのAPIをいくつか紹介します
事前アンケートからペンタブレットやCSSなどのキーワードがあったのでその辺からも拾っています
今日は主に既に勧告になっているものやWICGで議論されていて、1つ以上のブラウザで実装されているもの(一部例外を除く)について話します
API紹介のコーナー
お品書き
Async Clipboard
Streams API
Virtual Keyboard
ペンを扱うAPI
content-visibility
Async Clipboard chrome.iconfirefox.iconsafari.icon
Unblocking clipboard access
Async Clipboard API | WebKit
Promiseが返ってくるので、非同期に使えるクリップボードAPI
navigator.clipboard.readText()
navigator.clipboard.read()
navigator.clipboard.writeText()
navigator.clipboard.write()
モダンブラウザで共通して書き込めるのは image/pngと text/plain
ChromeはM86からtext/html https://bugs.chromium.org/p/chromium/issues/detail?id=931839
image/jpgのissue
https://bugs.chromium.org/p/chromium/issues/detail?id=954390
https://bugzilla.mozilla.org/show_bug.cgi?id=1610286
Streams API chrome.iconfirefox.iconsafari.icon
https://developer.mozilla.org/en-US/docs/Web/API/Streams_API
Streams APIをちゃんと理解する - Speaker Deck
ReadableStream / WritableStream / TransformStream
ReadableStreamは全てのモダンブラウザで利用可能
例: FetchのResponse.bodyはReadableStream
ReadableStreamは合成可能
Fetchで受けたReadableStreamの前後に新たなReadableStreamを合成する
code: stream-fetch.js
const startFetch = caches.match('/shell-start.cbd594dfa81d.inc');
const endFetch = caches.match('/shell-end.cbd594dfa81d.inc');
const middleFetch = fetch(url).then(response => {
if (!response.ok && response.status != 404) {
return caches.match('/error.ba6821d4f751.inc');
}
return response;
}).catch(err => caches.match('/offline.d989ddb2d13b.inc'));
function pushStream(stream) {
const reader = stream.getReader();
return reader.read().then(function process(result) {
if (result.done) return;
controller.enqueue(result.value);
return reader.read().then(process);
});
}
startFetch
.then(response => pushStream(response.body))
.then(() => middleFetch)
.then(response => pushStream(response.body))
.then(() => endFetch)
.then(response => pushStream(response.body))
.then(() => controller.close());
}
https://gist.github.com/jakearchibald/64e26e7a1d9b06b3fa3ec0383f2b1f91
ReadableStreamの作り方
new ReadableStream
code: stream.js
const stream = new ReadableStream({
start(controller) {
interval = setInterval(() => {
let string = randomChars();
controller.enqueue(string);
if (Math.random > 0.95) controller.close()
}, 100);
},
cancel() {
clearInterval(interval);
}
});
WebRTCなどから作る
MediaStreamから変換する
HTMLCanvasElement.captureStream
MediaRecorder
MediaStream Recording API - Web APIs | MDN
TextEncoderで Uint8Array を得る
Workerとのやり取りに使う(Chrome flag: enable-experimental-web-platform-features)
StreamsをpostMessage出来るようにする目論見がある
Transferable Streams
https://gyazo.com/f9a6c8a94e409dc54478fb5bbe9560c6
改行区切りとかでWorkerにメッセージを送り続けることが可能
ChromeではFetchのRequest.bodyにもReadableStreamが使えるようになった(Chrome 85b /w flag: enable-experimental-web-platform-features)
/nwtgck/Webブラウザ上で純粋なHTTPだけで単方向リアルタイム通信を可能にするHTTPのストリーミングアップロードが遂にやってくる
websocketみたいに使えるかも
HTTPのレイヤで使えるので、Proxyとかも考えるとちょっと楽
Virtual Keyboard
https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/VirtualKeyboardAPI/explainer.md
主にSurface上のMSEdgeを意識してVirtual Keyboardを適切に扱うためのAPI提案
まだChromiumにも未実装です https://bugs.chromium.org/p/chromium/issues/detail?id=856269
上手くいくとiOSのキーボードも同じように扱える期待は高い
https://gyazo.com/942243619126420daf518741e7de6c97
こういうことが出来るようになる予定
code: sample.js
window.navigator.virtualKeyboard.overlaysContent = true;
navigator.virtualKeyboard.addEventListener("geometrychange", (evt) => {
let { width, height } = evt.boundingRect;
if( width !== 0 && height !== 0 ) {
console.log('virtual keyboard is now visible!')
}
document.querySelector(".search-box").style.bottom = ${height + 15}px;
});
code: sample.css
.search-box {
position: absolute;
bottom: env(keyboard-inset-bottom);
}
css env
css media-query prefers-color-schema でダークモードかどうか取れる
ペンを扱うAPI chrome.iconfirefox.iconsafari.icon
Touch events
TouchEvent.touches: Touch[]
Touch
touch.touchType: 種類が取れる
direct, stylus
Touch.azimuthAngle / Touch.altitudeAngle: 向き
https://gyazo.com/c9409b0e09515713f828e7aaa27867e2
from: Illustrating the Force, Altitude, and Azimuth Properties of Touch Input | Apple Developer Documentation
Touch.force: 圧力(0 - 1) float
PointerEvent
PointerEvent.touchType === 'pen': ペンかどうか
touch, mouse
PointerEvent.pressure: 圧力(0 - 1) float
PointerEvent.twist: 角度(0 - 359)
Pen Events https://www.chromestatus.com/feature/5745797339545600
https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/PenEvents/explainer.md
Surface Pro penやApple Pencilなどのペン自体のイベントを扱えるようにするAPIの提案
penbuttonclick, penbuttondblclick
penbuttonpressandhold: ボタンが押したままのときは消しゴムにするとか
pendockchange: dockに格納されたらお絵かきのモードを切り替えるとか
CSS: content-visibility chrome.icon
Chrome 85より利用可能
元々あったCSS Containmentを拡張したCSS Containment Module Level 2の仕様の中の1つ
https://gyazo.com/96fea1fc34515e08fbb6029edee676ab
Webアプリケーションで 60fpsを(極力)目指す - Speaker Deck
content-visibility: autoを指定して要素をchunk分割することでレンダリングを最適化できる
loading="auto"のcontent-visibility版
https://gyazo.com/b4e03ce1e1323b1dea6aaf6df40deddc
content-visibility: the new CSS property that boosts your rendering performance
containのlayout, style, paintが当たってるのと同じになり、画面外のものはsizeも含む
contain-intrinsic-sizeでplaceholderのようにサイズを指定できる
content-visibility: hiddenを使うとrendering stateは維持されたまま非表示に出来る
display: none: rendering stateが破棄されるので、再度表示する際には新規にレンダリングするのと同じコストがかかる
visibility: hidden: rendering stateは維持されるが、子要素含めてドキュメント上に残り、またblockスペースは維持される
content-visibility: hidden-matchable
レンダリングはされないが、ページ内検索やScroll To Text Fragmentで発見可能な要素
利用する際はbeforematchイベントと組み合わせる
Chrome 85よりflag付きで利用可能
まとめ
ざっと名前だけだと60以上のブラウザで使えるAPIを紹介しました
この中のもののいくつかが全てのモダンブラウザで使えるようになるかは…
モダンブラウザだと色々出来るので積極的に使っていきましょう
Chromeでしか動かないものも多いが…
UAで判別せずにfeature detectionしよう
Slackの#frontendで常に紹介したりしているので覗いてみてください
追記コーナー
ブコメなどでの反応へ返答
"Web API"はGoogle Maps APIなどのようなウェブサービスが提供することでJavaScriptのAPIのことは指さないのではないか
例えば、MDNでもWeb APIsとしてここで紹介したようなJavaScriptやCSSなどで利用可能なAPIの一覧が記載されています。まぁややこしいという意見は受け入れますが、そう呼ばれているので仕方ないですね…