Frontend Weekly 2023-02-22
Safari 16.4 beta
2023 年 2 月にリリースされた iOS 16.4 beta 1 及び Safari 16.4 beta について、いくつか紹介します。
Web Push のサポート
今までは Android などでしかサポートされていなかった Web Push が、iOS 16.4 beta 1 でサポートされました。 ホーム画面に追加された Web アプリから、Push API、Notifications API、Service Worker などを駆使して、ユーザーにプッシュ通知を送ることが可能になります。
またホーム画面に追加された Web アプリでカウントを表示できる Badging API などもサポートされ、今後 PWA の利用が広がると期待されます。
https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/
Many ECMAScript features supported
Safari 16.4 beta は、非常に巨大なリリースです。Web Push だけでなく ECMAScript の多くの機能が新たにサポートされました。
https://developer.apple.com/documentation/safari-release-notes/safari-16_4-release-notes
以下に、サポートされた機能のいくつかを軽く紹介します。
Array.formAsync
Array.from が for 相当なのに対して、Array.fromAsync は for await と見れば理解しやすいと思います。 Async iterable を処理する方法として、Promise.all などがありますが、Promise.all が並列実行であるのに対して、 Array.fromAsync は for await 相当であり、順次実行されます。
Array#group, Array#groupToMap
Array#group は、配列を指定した関数の戻り値でグルーピングしたオブジェクトを返します。 一方、Array#groupToMap は、配列を指定した関数の戻り値でグルーピングした Map を返します。
https://github.com/tc39/proposal-array-grouping
コードを見た方が理解しやすいと思います。
const animals = [ { name: "たま", type: "猫" }, { name: "みけ", type: "猫" }, { name: "ぽち", type: "犬" },];console.log(animals.group((animal) => animal.type));/* result{ 猫: [ { name: 'たま', type: '猫' }, { name: 'みけ', type: '猫' }, ], 犬: [ { name: 'ぽち', type: '犬', }, ],}*/console.log(animals.groupToMap((animal) => animal.type).get("猫"));/* result[ { name: 'たま', type: '猫' }, { name: 'みけ', type: '猫' },]*/
Import Maps
ブラウザで実行される import によって読み込まれるパッケージの URL を指定する手段です。
https://github.com/WICG/import-maps#multiple-import-map-support
<head> <script type="importmap"> { "imports": { "react": "https://unpkg.com/react@18/umd/react.development.js", "react-dom": "https://unpkg.com/react-dom@18/umd/react-dom.development.js" } } </script></head><body> <script type="module"> import { createRoot } from "react-dom/client"; import React from "react"; </script></body>
AV1 のサポート
AV1 コーデックが Safari 16.4 beta でサポートされました。 しかし、Apple の M1/M2 は AV1 用のハードウェアアクセラレータを搭載していないため、利用できる環境はほぼありません。
Chrome 110
2023 年 2 月にリリースされた Chrome 110 について、いくつか紹介します。
古い Windows OS のサポートが終了
Chrome 110 で、Windows 7/8/8.1 などの OS のサポートが終了しました。 なお 2023 年 1 月に、Microsoft は Windows 7/8/8.1 のほとんどのバージョンのサポートを終了しています。
また最後のサポートバージョンである Chrome 109 へのセキュリティ修正も 2023 年 10 月までとなっています。
R.I.P.
PIP 擬似クラスのサポート
PIP(Picture in Picture)とは、再生している動画を画面の隅に別ウィンドウで表示する機能です。
PIP を利用している video 要素に対してスタイルを適用できる:picture-in-picture
疑似クラスが Chrome 110 でサポートされました。
:picture-in-picture
は:
が 1 つだけであり、::after
や::first-letter
のような擬似要素ではありません。
PIP で表示される別ウィンドウを表すものではなく、PIP を利用している video 要素を表す点に注意してください。
https://developer.chrome.com/blog/new-in-chrome-110/
Chrome Developers の記事では、PIP モードである video 要素のデフォルトの見た目を上書きするデモが紹介されています。
video:picture-in-picture { opacity: 0;}.video-container { background: #000; position: relative;}.video-container:has(video:picture-in-picture)::before { content: "Video is now playing in a Picture-in-Picture window"; position: absolute; right: 36px; bottom: 36px; color: #ddd;}
現状、PIP を利用する機会はあまりないかもしれませんが、Chrome 111 では PIP が任意の要素に対して利用できるdocumentPictureInPictureのサポートが予定されており、 今後は利用する機会が増えるかもしれません。
TypeScript 5.0 Beta
2023 年 1 月に TypeScript 5.0 Beta がリリースされました。正式版は 2023 年 3 月が予定されています。 なお、TypeScript はセマンティックバージョニングに準拠していないため、5.0 は重要な変更が含まれていることを意味しません。
実際、allowImportingTsExtensions
やmoduleResolution: "bundler"
、verbatimModuleSyntax
などのフラグや、extends
に複数の設定ファイルを記述できるようになるなど
コンパイラ周りの変更には興味深いものが多くあるものの、tsconfig.json
の変更を滅多にしない多くのライトユーザーにとっては、すぐさま影響のあるバージョンではないと思われます。
以下では、今後誰でも使う機会がありそうな新機能について、いくつか紹介します。
https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/
Decorators
TypeScript 5.0 では、TS39 の Stage3 相当のデコレータの実装が予定されています。 今後、デコレータを利用したライブラリが多く登場すると予想されます。
なお、今までコンパイラフラグの--experimentalDecorators
で利用できたデコレータ(Legacy Decorators と呼称される)は、古いプロポーザルを元にしたものであり、互換性がないことには注意が必要です。
ただしexperimentalDecorators
が削除される予定はなく、TypeScript 5.0 には、experimentalDecorators
を有効にした際の挙動改善も含まれています。
// Legacy Decorators@registerexport class Foo {}export class C { constructor(@inject(Foo) private x: any) {}}
// New decorators proposalexport@registerclass Foo {}export class C { // Cannot use decorators as arguments. constructor(@inject(Foo) private x: any) {}}
const Type Parameters
今まで、あるオブジェクトのプロパティを取得する関数を実装した際に、具体的な型が欲しければ、呼び出す度に毎回引数へas const
を付ける必要がありました。
TypeScript 5.0 では、型パラメータにconst
修飾子を付けることで、引数側でas const
を付ける必要がなくなります。
/*TypeScript 4.9*/type HasNames = { readonly names: string[] };function getNamesExactly<T extends HasNames>(arg: T): T["names"] { return arg.names;}
// Inferred type: string[]const names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] });
// Inferred type: readonly ["Alice", "Bob", "Eve"]const names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] as const });
/*TypeScript 5.0*/type HasNames = { names: readonly string[] };function getNamesExactly<const T extends HasNames>(arg: T): T["names"] { return arg.names;}
// Inferred type: readonly ["Alice", "Bob", "Eve"]// Note: Didn't need to write 'as const' hereconst names = getNamesExactly({ names: ["Alice", "Bob", "Eve"] });
Next.js v13.2
弊社のいくつかのサービスとこの技術ブログは現在 Next.js で構築されており、特にこの技術ブログでは、未だ実験的な機能である App directory も利用しています。
以下では、2023 年 2 月にリリースされた Next.js v13.2 から、お世話になりそうな機能をいくつか紹介します。
https://nextjs.org/blog/next-13-2
Metadata API によるビルトイン SEO サポート
今までの head.js が非推奨になり、代わりに Metadata API が利用できるようになりました。
メタデータが静的な場合は、metadata を layout.js や page.js から export し、動的な場合は、 generateMetadata メソッドを export します。
import type { Metadata } from "next";
// 静的な場合export const metadata = { viewport: "width=device-width, initial-scale=1", title: "My App", description: "My App Description", openGraph: { type: "website", // ... }, twitter: { card: "summary", //... },} satisfies Metadata;
// 動的な場合、記事ページなどexport async function generateMetadata({ params, searchParams,}): Promise<Metadata> { const data = await getData(params.id); const metadata = { title: data.title, // ... } satisfies Metadata; return metadata;}
Metadata API では、設定がルートからマージされていきます。head.js ではページ毎に設定する必要がありました。
次の例では、app/page.js
で設定した twitter の設定が、app/about/page.js
の設定に引き継がれます。
export const metadata = { title: "My App", description: "My App Description", twitter: { card: "summary", site: "@site", creator: "@creator", images: "https://example.com/image.png", },} satisfies Metadata;
// app/about/page.jsexport const metadata = { title: "About", description: "About Description", // twitterの設定が引き継がれる} satisfies Metadata;
また、どのページでも後ろ側にブランド名を入れたいといったケースに簡単に対応できる機能もあります。
次の例では、これを指定したページ以下の階層でtitle
にAbout
を指定すると、About|My App
のようなタイトルになります。
export const metadata = { title: { default: "My App", template: `%s | My App`, },};
Custom Route Handlers
pages/api
の App directory バージョンです。
今まで App directory であっても、API を実装したい場合はpages/api
を追加する必要がありました。
ですが今後はpage.js
の代わりにroute.js
を追加するだけで、API を実装できるようになります。
Statically Typed Links (Beta)
Link コンポーネントの href に型が付くようになり、存在しないページへのリンクを防ぐことができます。
この機能はapp
ディレクトリだけでなく、pages
ディレクトリでも利用できます。
ただし、ベータ版であるため、next.config.js
にexperimental.typedRoutes
を追加する必要があります。
/** @type {import('next').NextConfig} */const nextConfig = { experimental: { typedRoutes: true, },};
module.exports = nextConfig;
ES2023
ECMAScript 2023 は、2023 年にリリースされる ECMAScript の仕様です。 なお ECMAScript は、前年に Stage 4 となった機能が次期 ECMAScript に含まれるという仕組みであり、 Stage 4 の条件として 2 つ以上の実装が必要であるため、次期 ECMAScript がほとんどのブラウザで既に実装されているということがよくあります。
以下では、ECMAScript 2023 に追加されたものを紹介します。Symbols as WeakMap keys は紹介しません。
Array find from last
全てのモダンブラウザで実装済みです。
const array = [1, 2, 3, 4];array.find((item) => item % 2 === 1); // 1array.findLast((item) => item % 2 === 1); // 3
array.findIndex((item) => item % 2 === 1); // 0array.findLastIndex((item) => item % 2 === 1); // 2
Hashbang Grammar
Node.js などと同様に、ファイルの先頭行にある#!
をコメントとして扱います。
これにより、例えばサーバーサイドとクライアントサイドで同じコードを使いまわすことができます。
なお、全てのモダンブラウザで実装済みです。
#!/usr/bin/env node// in the Script Goal"use strict";console.log(1);
Change Array by copy
非破壊的な配列の操作をするメソッド群です。 これらが追加されると、Array.prototype.slice()などを利用したハックをしなくても済みます。 ただし、ほとんどのブラウザで未実装です。
const array = [2, 6, 3];array.toReversed(); // [3, 6, 2]array.toSorted(); // [2, 3, 6]array.with(1, 2); // [2, 2, 3]
Lighthouse 10
2023 年 2 月に Lighthouse 10 がリリースされました。
https://developer.chrome.com/blog/lighthouse-10-0/
TTI の削除
操作可能になるまでの時間を表す指標である Time To Interactive(TTI)が削除されました。 TTI が占めていたスコアウェイトは、CLS に移行されました。
削除された理由としては、ランキングで利用される Core Web Vitals の指標ではない点、Core Web Vitals の指標であるインタラクティブ性(FID)を測定するには TTI よりも Total Blocking Time(TBT)の方がより良い指標である点などが考えられます。 FID や TTI、TBT の関係性については次の図を参考にしてください。
なお、よく誤解されますが Lighthouse と Core Web Vitals には直接的な関連はありません。つまり、この変更は SEO に影響がありません。
Squoosh
Squoosh CLI 及び libsquoosh が非推奨に
Squoosh は、Google が開発した画像圧縮ウェブアプリです。また、Squoosh CLI は、Squoosh の圧縮機能をコマンドラインから利用できるようにしたものです。
ですが、2023 年 1 月に経済状況などから取り組む時間や人がいないというコメントと共に、Squoosh の CLI 及び libsquoosh のコードがリポジトリから削除されました。
なお、数日後に Google では 1 万 2000 人(全従業員の 6%)の解雇を発表しています。