Cybozu Frontend Monthly #51

タイトル画像

イベント概要

サイボウズフロントエンドマンスリー は、サイボウズ社内で行っているフロントエンド情報共有会「フロントエンドウィークリー」の公開版です。

その月に気になったフロントエンドの情報を、サイボウズのフロントエンドエキスパートチームのメンバーが共有していきます。

このイベントのハッシュタグは #サイボウズフロントエンドマンスリー です。

※フロントエンドウィークリーとは

毎週火曜の 17:00 〜 18:00 で社内向けに行っているフロントエンドの気になる記事を紹介する会です。2016年3月15日から行われています。
ハッシュタグ #サイボウズフロントエンドウィークリー で実況しています。

zennのpublicationにてウィークリーのまとめも投稿していますので、ぜひこちらもご覧ください。 https://zenn.dev/p/cybozu_frontend

開催日

2024年10月29日

イベントページ

https://cybozu.connpass.com/event/333156/

配信URL

https://www.youtube.com/watch?v=w4SNE4RiZ1c

メンバー


コンテンツ

👀 Notable Articles

Svelte 5 is alive

Svelte 5 がリリースされました。

今回のアップデートでは rune のサポートによって基礎的な記法が大幅に変更されています。

例えば、count というリアクティブオブジェクトを作成する場合、Svelte4 以前だと

let count = 0

となりますが、Svelte 5 では

let count = $state(0);

となります。

また、slot でのコンポーネント結合が非推奨となり、snnipets による合成がサポートされました。

基本的な children の受け渡しについて、Svelte 4 以前は <slot /> をコンポーネントに差し込み、親コンポーネントが slot を受け取る仕組みでしたが、Svelte 5 では $props から children を取得してレンダーするようになりました

<script>
  let { children } = $props();
</script>

{@render children?.()}

Svelte コンポーネントが Class ではなくなっているため、今後コンポーネントを呼び出す際は mounthydrate といった新たな API を呼び出す必要があります。

詳細な Svelte 4 以前との比較は Svelte 5 migration guide 参照。

First-class Vitest integration

Storybook の 8.3 で Vitest の integration がファーストクラスでサポートされました。

今まで Story を実際にブラウザ上でテストするには Chromatic か Storybook が提供するテストランナーを使うという選択肢しかありませんでしたが、今回のリリースで Vitest のブラウザモード使うことができるようになります。

ドキュメントを見ると、experimental ではありますが、Storybook が提供する Vitest 用のプラグインを setup ファイルや Vitest の config で読み込むことで、Vitest 側で Story 上のテストを実行できるようになります。

Vite を採用するプロダクトであれば、今回のリリースで、ブラウザ上でコンポーネントテストする際の選択肢が増えるのでとても良いですね。

New Values and Functions in CSS

2024 年 9 月に W3C より 公開された CSS Values and Units Module Level 5 の Working Draft の内容について、新たに追加された機能についてピックアップして紹介している記事です。従来の CSS では複雑な記述が必要だったものが簡潔に表現できたり、不可能だったことが可能になっていたりと、注目したい機能が多く含まれています。

中でも自分が特に気になったものを幾つか紹介します。

calc-size()

従来でも calc() を使うことで計算結果を元にしたサイズを利用できましたが、Intrinsic Size(内在サイズ)を元にした計算は不可能でした。具体的には、automin-contentmax-contentfit-contentなどです。

一方、calc-size() では、Intrinsic Size を元にした計算ができます。代表的な利用例としては、アコーディオンメニューの開閉アニメーションで、開閉後の高さを auto のままアニメーション可能になったりします。

random() random-item()

random() は指定した範囲内からランダムな値を返します。たとえば random(100px, 300px, by 50px) とした場合、100px・150px・200px・250px・300px のうちいずれかを返します。一方、random-item() はリスト内からランダムでピックアップします。 random-item(100px, 200px, 500px) は、100px・200px・500px のいずれかを返します。従来 CSS 単体で乱数を扱うことはできなかったため、可能性が広がる機能ですね。

sibling-count() / sibling-index()

sibling-count() は兄弟要素の数を返し、sibling-index() は兄弟要素のうち自身のインデックスを返します。たとえば、grid レイアウトにおいて兄弟要素数に応じて columns の数を分割したいケースや、兄弟要素の中で自分が何番目に位置するかによってスタイルを変えたいケースなどで活用できます。

TC39 Advances 10+ ECMAScript Proposals: Key Features to Watch

2024 年 10 月の 8~9 で開催された TC39 の 104th meeting で 10 個以上の Proposal に Stage の Update があり、うち5つは Stage4 になりました。Stage4 になったものは来年の ES2025 として標準化され、メジャーな JS ランタイムでは利用可能になる予定です。今回はそんな Stage4 になった Proposal について紹介します。

Iterator Helpers

Iterator Helpers は Iterator オブジェクトに対して Array と同じような .map() , .filter() といったヘルパーメソッドを実装する提案です。Iterator は大規模なデータや長さの確定していないデータを効率的に管理できるというメリットがありますが、変換・操作できるメソッドが存在しないため、うまく活用できていないケースや代わりに配列が利用されるケースが目立っていました。

Iterator Helpers が導入されることで、多少挙動が違うものの普段慣れ親しんた Array のメソッドと同じ感覚で Iterator オブジェクトを利用できるようになります。

Import Attributes と JSON Modules

Import Attributes は import 文の構文を拡張し、モジュール指定子とは別に情報を指定できるようにする Proposal です。主な用途として JS 以外のモジュールのサポートが想定されています。構文としては今までの import 文の後ろに with {[key]:[value]} という形で情報を追加します。

import json from "./foo.json" with { type: "json" };

またこの Import Attributes から派生・分離した Proposal が JSON Modules です。JSON modules は JSON をモジュールとして読み込んだ時の挙動を統一するための Proposal で、ランタイムによらない JSON 読み込みの動作を定義しています。JSON Modules は Import Attributes を利用して読み込まれることを前提に作られています。

これら2つの Proposal が Stage4 になることで JSON の統一された読み込みがサポートされ、今ままで以上に JSON の利用が手軽かつ安全になりそうです。

Regular Expression Pattern Modifiers

JavaScript 以外の多くの言語では実装されている正規表現の Modifiers 機能を JavaScript でもサポートする Proposal です。Modifiers は正規表現にで指定可能なフラグを部分的に適用(または取消)することができる構文です。 具体的には (?[flag]:) で部分的なフラグの有効化、 (?-[flag]:) で部分的なフラグの無効化が可能です。以下の例では、全体に i フラグがついているため基本的に大文字小文字は区別されませんが、2文字目は (?-i:...)i フラグを無効化しているため大文字小文字を区別します。

const re1 = /^[a-z](?-i:[a-z])$/i // 1文字目は大文字小文字どちらても良いが2文字目は小文字だけ

Promise.try

Promise.try() は Promise を返す関数かどうかに関わらず、ラップした関数の返り値を Promise にするメソッドです。Promise にするだけであれば Promise.resolve().then(f) のように書けば良いのですが、この場合関数の実行は必ず次の tick になり同期的でなくなります。そこで処理自体は同期的に行いつつ、Promise と同じセマンティクスを得るための簡単な記法を提供するのがPromise.try()です。これにより同期関数も非同期関数も最適化されながら同じセマンティクスで実行可能になります。

🗓 Monthly Articles

📖 Framework, Library

⚡️ Services

🖥 Browsers

📝 Specifications

🦆 Others

フロントエンドエキスパートチームについて

https://speakerdeck.com/cybozuinsideout/frontendexpert-team