2880 文字
14 分

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 相当であり、順次実行されます。

https://github.com/tc39/proposal-array-from-async

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 は重要な変更が含まれていることを意味しません。

実際、allowImportingTsExtensionsmoduleResolution: "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
@register
export class Foo {}
export class C {
constructor(@inject(Foo) private x: any) {}
}
// New decorators proposal
export
@register
class 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' here
const 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の設定に引き継がれます。

app/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.js
export const metadata = {
title: "About",
description: "About Description",
// twitterの設定が引き継がれる
} satisfies Metadata;

また、どのページでも後ろ側にブランド名を入れたいといったケースに簡単に対応できる機能もあります。 次の例では、これを指定したページ以下の階層でtitleAboutを指定すると、About|My Appのようなタイトルになります。

export const metadata = {
title: {
default: "My App",
template: `%s | My App`,
},
};

https://beta.nextjs.org/docs/api-reference/metadata

Custom Route Handlers#

pages/apiの App directory バージョンです。

今まで App directory であっても、API を実装したい場合はpages/apiを追加する必要がありました。 ですが今後はpage.jsの代わりにroute.jsを追加するだけで、API を実装できるようになります。

https://beta.nextjs.org/docs/routing/route-handlers

Link コンポーネントの href に型が付くようになり、存在しないページへのリンクを防ぐことができます。 この機能はappディレクトリだけでなく、pagesディレクトリでも利用できます。 ただし、ベータ版であるため、next.config.jsexperimental.typedRoutesを追加する必要があります。

next.config.js
/** @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); // 1
array.findLast((item) => item % 2 === 1); // 3
array.findIndex((item) => item % 2 === 1); // 0
array.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%)の解雇を発表しています。

https://github.com/GoogleChromeLabs/squoosh/pull/1321

Frontend Weekly 2023-02-22
https://blog.ohirunewani.com/series/frontend-weekly/2023-02-22/
作者
hrdtbs
公開日
2023-02-22
ライセンス
CC BY-NC-SA 4.0