<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds/rss-style.xsl" type="text/xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Nevermind</title>
        <link>https://blog.m1ng.space/ja</link>
        <description>m1ngsamaのブログ</description>
        <lastBuildDate>Thu, 13 Aug 2026 08:51:49 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>Astro-Theme-Retypeset with Feed for Node.js</generator>
        <language>ja</language>
        <copyright>Copyright © 2026 m1ngsama</copyright>
        <atom:link href="https://blog.m1ng.space/ja/rss.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[自分だけのオペレーティングシステムを構築する方法]]></title>
            <link>https://blog.m1ng.space/ja/posts/myarch/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/myarch/</guid>
            <pubDate>Tue, 20 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Arch Linuxはミニマリズムを採用しており、ユーザーが望む機能を自由に構築できます。以下では、実際のマシンへのデプロイを例に、Arch...]]></description>
            <content:encoded><![CDATA[<p>Arch Linuxは<a href="https://wiki.archlinux.org/title/Arch_Linux">ミニマリズム</a>を採用しており、ユーザーが望む機能を自由に構築できます。以下では、実際のマシンへのデプロイを例に、Arch Linuxを構築する方法を簡単に紹介します。</p>
<h2>準備</h2>
<p>必要なもの：コンピュータ、USBドライブ（または任意の可搬型ストレージデバイス）、インターネット接続、基本的な情報検索スキル</p>
<ul>
<li>どのインストールイメージを使用する場合でも、オフライン版イメージであっても、インターネット接続を準備することをお勧めします。これにより、カーネルやツールの更新が確実に行えます。経験豊富な場合は、必要に応じて判断してください。</li>
<li>Wi-Fiを使用する場合、ネットワーク名は英語にしてください。tty環境では非ASCII文字（日本語など）が表示できず、認識できないブロック文字として表示されます。</li>
<li>同一ディスクにデュアルブートを計画している場合、Arch Linux用に十分なディスク容量を確保してください。将来のソフトウェアインストールのために、少なくとも100GBを推奨します。また、EFIパーティションの容量が256MB以上であることを確認するか、<a href="https://wiki.archlinux.org/title/EFI_system_partition">追加のマウントポイントを作成</a>してください。</li>
<li>Windows 10のパーティションがBitLocker暗号化を有効にしているか確認してください。事前にリカバリーキーを取得し、電源設定の「高速スタートアップ」を無効にしてください！</li>
</ul>
<blockquote>
<p>操作前に、内容をよく読み、理解できない部分は検索して学習してください。慎重に操作し、定期的にバックアップを取ってください。データは貴重です。</p>
</blockquote>
<h2>インストールメディアの作成</h2>
<ol>
<li><a href="https://archlinux.org/download/">Arch Linux公式ダウンロードページ</a>からのみインストールイメージをダウンロードしてください。Arch Linuxはローリングリリースディストリビューションであることに注意してください。</li>
<li>カーネルを自分でコンパイルしたい場合は、<a href="https://wiki.archlinux.org/title/Kernel/Traditional_compilation">カーネル/従来のコンパイル</a>を参照してください。</li>
<li>公式のインストールイメージを使用する場合、<a href="https://www.ventoy.net/">Ventoy</a>を使用してブータブルUSBを作成することをお勧めします。</li>
</ol>
<h2>基本インストール</h2>
<h3>1. Arch Linuxメディアからのブート</h3>
<blockquote>
<p>電源を切り、USBドライブを挿入して起動します。BIOSに入り、USBを起動デバイスとして選択し、最初のオプションを選んでEnterキーを押すと、Arch Linuxインストール環境に入ります。</p>
</blockquote>
<h3>2. UEFIの確認</h3>
<pre><code>systemctl stop reflector.service
# 自動ミラー更新を無効にします。地理的なネットワーク環境により問題が発生する可能性があるためです。
</code></pre>
<pre><code>ls /sys/firmware/efi/efivars
# EFI変数が一覧表示された場合、UEFIモードで起動しています。2025年のほとんどのマシンはUEFIブートです。
</code></pre>
<h3>3. ネットワーク設定</h3>
<blockquote>
<p>Arch Linuxのインストールにはインターネット接続が必要です。オフラインインストールはより複雑で、<a href="https://wiki.archlinux.org/title/Offline_installation">オフラインインストール</a>を参照してください。</p>
<p>有線接続の場合、LANケーブルを接続し、インターフェースのLEDが点滅しているか確認してください。数秒待つと接続が確立します。</p>
<p>キャンパスネットワーク環境では、上位ルーターでの認証が必要な場合があります。<a href="https://github.com/nbtca/nbtverify">nbtverify</a>プロジェクトを参照してください。</p>
<p>Wi-Fiの場合は、<code>iwctl</code>を使用して接続します。</p>
</blockquote>
<pre><code>lspci -k | grep Network
# 無線アダプターが動作しているか確認します。問題がない場合はこの手順をスキップできます。
</code></pre>
<blockquote>
<p>カーネルが無線ドライバーをロードしているか確認します。</p>
<p>以下のような表示が期待されます：<code>00:14.3 Network controller: Intel Corporation Wi-Fi 6 AX201 (rev 20)</code>。</p>
<p>表示がない場合、無線接続が無効（blocked: yes）になっていないか確認します。</p>
</blockquote>
<pre><code>rfkill list
# 無線アダプターは通常wlan0と呼ばれます。
</code></pre>
<pre><code>ip link set wlan0 up
# 「Operation not possible due to RF-kill」などのエラーが出た場合：
rfkill unblock wifi
</code></pre>
<pre><code># iwctlを使用してWi-Fiに接続
iwctl # 対話モードに入る
device list # 無線デバイス（例：wlan0）を一覧表示
station wlan0 scan # ネットワークをスキャン
station wlan0 get-networks # 利用可能なWi-Fiネットワークを一覧表示
station wlan0 connect wifi-name # ネットワークに接続。日本語名はサポートされません。パスワードを入力してEnter
exit # 接続成功後に終了

ping www.google.com # ネットワーク接続性をテスト
</code></pre>
<blockquote>
<p>ネットワーク設定に問題がある場合、<a href="https://wiki.archlinux.org/title/Network_configuration/Wireless">ネットワーク設定/無線</a>を参照してください。</p>
</blockquote>
<h3>5. システムクロックの同期</h3>
<pre><code>timedatectl set-ntp true # システム時間をネットワーク時間と同期
timedatectl status # サービス状態を確認
</code></pre>
<h3>6. ミラーリストの更新（日本国内の場合）</h3>
<pre><code>vim /etc/pacman.d/mirrorlist # ミラーリストを編集
Server = https://mirrors.cat.net/archlinux/$repo/os/$arch # 日本のミラー
Server = https://ftp.tsukuba.wide.ad.jp/Linux/archlinux/$repo/os/$arch # 筑波大学
Server = https://mirror.osbeck.com/archlinux/$repo/os/$arch # Osbeckミラー
</code></pre>
<h3>7. Btrfsパーティションの作成</h3>
<h4>ディスク情報の確認</h4>
<pre><code>lsblk
</code></pre>
<p>現在のディスクのパーティション状況を表示します。<strong>Arch Linuxをインストールするターゲットディスクを慎重に確認してください</strong>。</p>
<p>ディスクの命名規則：</p>
<ul>
<li><strong>SATAドライブ</strong>：<code>sda</code>、<code>sdb</code>、<code>sdc</code> … パーティション：<code>sda1</code>、<code>sda2</code> など</li>
<li><strong>NVMeドライブ</strong>：<code>nvme0n1</code>、<code>nvme1n1</code> … パーティション：<code>nvme0n1p1</code>、<code>nvme0n1p2</code> など</li>
</ul>
<blockquote>
<p>この例ではSATAディスクを使用します。実際のディスクに応じて<code>/dev/sdx</code>を置き換えてください。</p>
</blockquote>
<pre><code>cfdisk /dev/sdx
</code></pre>
<p>使いやすいTUIパーティションインターフェースが表示されます。😄</p>
<h4>パーティションの操作手順</h4>
<h5>1. Swapパーティションの作成</h5>
<ul>
<li>矢印キーで<strong>Free space</strong>を選択。</li>
<li><code>[New]</code>を押してEnter、サイズを入力（RAMの60%～100%を推奨）。</li>
<li><code>[Type]</code>を押し、<strong>Linux swap</strong>を選択。</li>
</ul>
<h5>2. ルートパーティションの作成（Btrfs用）</h5>
<ul>
<li>残りのFree spaceを選択し、<code>[New]</code>を押してEnter。</li>
<li>サイズを入力（デフォルト：残りの全スペースを使用）。</li>
<li>タイプはデフォルトの<strong>Linux filesystem</strong>のまま。</li>
</ul>
<h5>3. パーティションテーブルの書き込み</h5>
<ul>
<li><code>[Write]</code>を選択し、<code>yes</code>を入力してEnter。
<blockquote>
<p>⚠️ <strong>注意：書き込みを行わないと、変更は反映されません！</strong></p>
</blockquote>
</li>
</ul>
<h4>パーティションのフォーマット</h4>
<h5>ディスクの再確認</h5>
<pre><code>fdisk -l
</code></pre>
<h5>EFIパーティションのフォーマット（新規作成の場合）</h5>
<pre><code>mkfs.fat -F32 /dev/sdxn
</code></pre>
<blockquote>
<p>💡 デュアルブートの場合、WindowsのEFIパーティションを再利用可能で、フォーマットは不要ですが、十分な空き容量を確認してください。詳細は<a href="https://wiki.archlinux.org/title/Dual_boot_with_Windows">Windowsとのデュアルブート</a>を参照。</p>
</blockquote>
<h5>Swapパーティションのフォーマット</h5>
<pre><code>mkswap /dev/sdxn
</code></pre>
<h5>Btrfsパーティションのフォーマット</h5>
<pre><code>mkfs.btrfs -L myArch /dev/sdxn
</code></pre>
<h4>Btrfsサブボリュームの作成とマウント</h4>
<pre><code>mount -t btrfs -o compress=zstd /dev/sdxn /mnt

# サブボリュームの作成
btrfs subvolume create /mnt/@        # ルートサブボリューム
btrfs subvolume create /mnt/@home    # /homeサブボリューム

umount /mnt
</code></pre>
<h4>⚠️ 最終確認</h4>
<ul>
<li>コマンドと操作を再確認してください！</li>
<li><strong>誤操作はデータ損失、特にWindowsパーティションの誤削除を引き起こす可能性があります 😥。</strong></li>
</ul>
<h3>8. パーティションのマウント（ルートから順に）</h3>
<pre><code>mount -t btrfs -o subvol=/@,compress=zstd /dev/sdxn /mnt # /ディレクトリをマウント
mkdir /mnt/home # /homeディレクトリを作成
mount -t btrfs -o subvol=/@home,compress=zstd /dev/sdxn /mnt/home # /homeディレクトリをマウント
mkdir -p /mnt/boot # /bootディレクトリを作成
mount /dev/sdxn /mnt/boot # /bootディレクトリをマウント
swapon /dev/sdxn # スワップパーティションを有効化
</code></pre>
<pre><code>df -h # マウントを確認
free -h # スワップパーティションのマウントを確認
</code></pre>
<h3>9. システムのインストール</h3>
<pre><code>pacstrap /mnt base base-devel linux linux-firmware btrfs-progs
# Btrfsを使用する場合、btrfs-progsパッケージを追加でインストール
</code></pre>
<pre><code>pacman -S archlinux-keyring
# GPGキーエラーが出た場合、イメージが最新でない可能性があります。archlinux-keyringを更新して解決。
</code></pre>
<pre><code>pacstrap /mnt networkmanager vim sudo zsh zsh-completions
# pacstrapスクリプトで必要な機能パッケージをインストール
</code></pre>
<h3>10. fstabファイルの生成</h3>
<blockquote>
<p>現在のマウント状況に基づいて、ディスクパーティションを定義するfstabを生成。</p>
</blockquote>
<pre><code>genfstab -U /mnt &gt; /mnt/etc/fstab
</code></pre>
<h3>11. 新しいシステムに入る</h3>
<pre><code>arch-chroot /mnt
# コードハイライトが消えた？心配無用、chrootに成功しています！
</code></pre>
<h3>12. ホスト名とタイムゾーンの設定</h3>
<pre><code>vim /etc/hostname
# マシンに名前を付けてください（特殊文字やスペースは避けてください。問題が発生する可能性があります。ホスト名を設定しないと、一部のGUIアプリが予期せず終了することがあります）。
</code></pre>
<pre><code>vim /etc/hosts
# hostsファイルを編集
</code></pre>
<blockquote>
<p>以下の内容を入力（myarchをあなたのホスト名に置き換え、間隔はタブで揃えます）：</p>
</blockquote>
<pre><code>127.0.0.1   localhost
::1         localhost
127.0.1.1   myarch.localdomain  myarch
</code></pre>
<pre><code>ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
# 東京タイムゾーンにシンボリックリンクを作成
</code></pre>
<pre><code>ls /usr/share/zoneinfo/
# 使用可能なタイムゾーンを確認し、必要に応じて上記コマンドのタイムゾーンを変更
</code></pre>
<h3>13. ハードウェアクロックの設定</h3>
<pre><code>hwclock --systohc
# システム時間をハードウェアクロックに同期
</code></pre>
<h3>14. ロケールの設定</h3>
<pre><code>vim /etc/locale.gen
# /etc/locale.genを編集し、en_US.UTF-8 UTF-8とja_JP.UTF-8 UTF-8の行頭のコメント（#）を解除
# このステップでソフトウェアの言語と文字セットを決定
</code></pre>
<pre><code>locale-gen
# ロケールを生成
</code></pre>
<pre><code>echo 'LANG=en_US.UTF-8' &gt; /etc/locale.conf
# locale.confを設定。日本語ロケールはttyで文字化けする可能性があるため推奨しません
</code></pre>
<h3>15. rootパスワードの設定</h3>
<pre><code>passwd root
# パスワード入力は非表示です。キーボードの不具合ではありません！😄
</code></pre>
<h3>16. マイクロコードのインストール</h3>
<pre><code>pacman -S intel-ucode # Intel CPU用
pacman -S amd-ucode # AMD CPU用
</code></pre>
<h3>17. Grubブートローダーのインストール</h3>
<pre><code>pacman -S grub efibootmgr os-prober
# grubはブートローダー、efibootmgrはNVRAMにブートエントリを書き込むために使用、os-proberはWindows 10の検出用
</code></pre>
<pre><code>grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=ARCH
# EFIパーティションにgrubをインストール
</code></pre>
<pre><code>vim /etc/default/grub
# ブートパラメータを編集
</code></pre>
<pre><code># "loglevel=3 quiet"を"loglevel=5 nowatchdog"に変更
# ファイル末尾に以下を追加：GRUB_DISABLE_OS_PROBER=false
</code></pre>
<ul>
<li>GRUB_CMDLINE_LINUX_DEFAULTの<code>quiet</code>パラメータを削除。</li>
<li><code>loglevel</code>を3から5に変更して、エラー時のデバッグを容易に。</li>
<li><code>nowatchdog</code>を追加して、起動/シャットダウンの速度を向上。</li>
<li><code>os-prober</code>を有効にしてWindows 10を検出。</li>
</ul>
<pre><code>grub-mkconfig -o /boot/grub/grub.cfg
# grubの設定ファイルを生成
# Windows 10が検出された場合、「Found Windows Boot Manager on /dev/nvme0n1p1@/EFI/Microsoft/Boot/bootmgfw.efi done」のような出力が表示されます
# Windowsが別のディスクにある場合、出力されないことがあります。システムに入った後、再マウントしてこのコマンドを再実行してください。
</code></pre>
<blockquote>
<p>全パラメータの詳細は<a href="https://wiki.archlinux.org/title/GRUB">Arch Wiki</a>を参照。</p>
</blockquote>
<h3>18. インストールの完了</h3>
<pre><code>exit # インストール環境に戻る
umount -R /mnt # 新しいパーティションをアンマウント
reboot # 再起動
</code></pre>
<blockquote>
<p>再起動後、rootアカウントでログイン。</p>
</blockquote>
<pre><code>systemctl enable --now NetworkManager # NetworkManagerサービスを有効化し即時起動
ping www.google.com # ネットワーク接続性をテスト
</code></pre>
<blockquote>
<p>Wi-Fiの場合：</p>
</blockquote>
<pre><code>nmcli dev wifi list # 近くのWi-Fiネットワークを表示
nmcli dev wifi connect "Wi-Fi SSID" password "ネットワークパスワード" # 指定のWi-Fiネットワークに接続
</code></pre>
<pre><code>nmtui
# nmtuiの方が使いやすいですよ！😄
</code></pre>
<pre><code>pacman -S fastfetch
fastfetch
# fastfetchをインストールしてシステム情報を確認
# 伝統的なneofetchの時間です！😄
</code></pre>
<pre><code>shutdown 0
shutdown -h now
poweroff
# 上記3つのコマンドはいずれもシャットダウンです。😄 電源ポリシーがまだ設定されていないので、きちんとシャットダウンしてください。
</code></pre>
<h2>おめでとう 🎉</h2>
<blockquote>
<p>これで、グラフィカルインターフェースなしの基本的なArch Linuxのインストールが完了しました！</p>
<p>グラフィカルインターフェースのガイドは次回の更新で公開予定ですが、いつものように：マニュアルをよく読んでください！</p>
<p>このガイドはきっかけに過ぎません。より多くの技術愛好者がコミュニティに参加してくれることを願っています！</p>
</blockquote>
<hr />
<blockquote>
<p>関連リンク：<a href="https://nbtca.space/">NBTCA</a></p>
</blockquote>
<ul>
<li>📧 NBTCAメール：<a href="mailto:contact@nbtca.com">contact@nbtca.com</a></li>
<li>🌐 NBTCA GitHub：<a href="https://github.com/nbtca">https://github.com/nbtca</a></li>
</ul>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[Hydration を深く理解する：モダンフロントエンドフレームワークの「必要悪」？]]></title>
            <link>https://blog.m1ng.space/ja/posts/frameworks/deep-dive-into-hydration/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/frameworks/deep-dive-into-hydration/</guid>
            <pubDate>Sat, 10 Aug 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[サーバーサイドレンダリング（SSR）は初期表示を高速化する一方、Hydration という概念とパフォーマンスコストをもたらします。それは何か、なぜ「操作の遅延」が生じるのか、そしてコミュニティはどのような代替策を模索しているのでしょうか。]]></description>
            <content:encoded><![CDATA[<h2>1. SSR の利点と悩み</h2>
<p>サーバーサイドレンダリング（SSR）は、Web アプリケーションの「初期画面の読み込み速度」（FCP）を大きく改善します。ブラウザは完全な HTML コンテンツを直接受け取ってすぐにレンダリングするため、ユーザーはページ内容を素早く確認でき、SEO と体感性能のどちらにも有利です。</p>
<p>しかし、この時点のページは「静的な殻」にすぎません。読み込みが完了したように見えても、ボタンのクリックや入力欄の操作には何の反応もありません。この静的なページに「命」を吹き込むために必要なプロセスが <strong>Hydration</strong>（ハイドレーション／活性化）です。</p>
<h2>2. Hydration とは？</h2>
<p>Hydration とは、クライアント側の JavaScript フレームワークが、サーバーでレンダリングされた静的 HTML を「引き継ぐ」プロセスです。</p>
<p>大まかな流れは次のとおりです。</p>
<ol>
<li>ブラウザがページに必要な JavaScript バンドル（React や Vue のランタイム、アプリケーションコードなど）をダウンロードして実行します。</li>
<li>フレームワークがメモリ上でコンポーネントツリーを再構築します。</li>
<li>フレームワークがサーバーでレンダリングされた DOM を走査し、<code>onClick</code> などのイベントリスナーを対応する DOM ノードに取り付けます。</li>
<li>フレームワークが、クライアント側のコンポーネント状態とサーバーレンダリング時の状態が一致していることを確認します。</li>
</ol>
<p>これが完了して初めて、ページは本当の意味で操作可能になります。Hydration は次のように考えられます。完成済みの LEGO 模型（HTML）を受け取ったものの、その一部を動かすには、組み立て説明書（JS）を最初から最後まで読み、すべてのブロックの位置を確認してから、その部品に電池を取り付けなければならない（イベントリスナーを追加する）、というイメージです。</p>
<h2>3. Hydration の問題：「操作できないインタラクティブ UI」</h2>
<p>Hydration は SSR ページを操作できない問題を解決しますが、それ自体が <strong>「不気味の谷」（Uncanny Valley）</strong> または <strong>「Hydration Gap」</strong> と呼ばれる新たなパフォーマンス上のボトルネックをもたらします。</p>
<p>これは、ユーザーがページ内容を目にする時点（FCP）から、ページが実際にユーザー操作へ応答できる時点（TTI）までに時間差があることを指します。その間、ページは使えるように見えますが、実際には「フリーズ」しています。</p>
<p>その原因は次のとおりです。</p>
<ul>
<li><strong>JS のダウンロードと実行によるブロック</strong>: Hydration を開始する前に、ブラウザは大量の JavaScript コードをダウンロード、解析、実行しなければなりません。</li>
<li><strong>高い起動コスト</strong>: ページの 90% が操作を必要としない静的コンテンツであっても、フレームワークはクライアント側でコンポーネントツリーの再構築とイベントリスナーの追加に多くの処理を行う必要があります。</li>
</ul>
<h2>4. Hydration の最適化と代替策</h2>
<p>Hydration のパフォーマンス問題を解決するため、コミュニティはより高度な複数のパターンを模索してきました。</p>
<h4>a. 部分 Hydration（Partial Hydration）</h4>
<p><strong>Astro</strong> が普及させた <strong>Islands Architecture（アイランドアーキテクチャ）</strong> は、部分 Hydration の代表的な実装です。核となる考え方は、デフォルトではすべてのコンポーネントが純粋な静的 HTML（JS ゼロ）のみを出力し、操作が必要なコンポーネントだけを明示的に「アイランド」として指定することです。</p>
<p>ビルド時、Astro はこれらの「アイランド」コンポーネントに対してのみ JavaScript をバンドルして送信します。そのため、ブラウザはページ全体ではなく数個の独立した部分だけを Hydrate すればよく、起動時に読み込んで実行する JavaScript の量を大幅に削減できます。</p>
<h4>b. 段階的 Hydration（Progressive Hydration）</h4>
<p>これは、優先順位に従ってコンポーネントを Hydrate する、より細粒度な最適化戦略です。たとえば、ビューポート内やユーザーがまもなく操作するコンポーネントを優先し、ページ下部にある重要度の低いコンポーネントの処理を遅らせることができます。</p>
<h4>c. 再開可能性（Resumability）</h4>
<p><strong>Qwik</strong> フレームワークは、Hydration を完全になくすことを目指す革新的な概念、<strong>Resumability（再開可能性）</strong> を提案しています。</p>
<p>その仕組みは次のとおりです。</p>
<ol>
<li><strong>シリアライズ</strong>: サーバー側で、Qwik はアプリケーションの全状態、コンポーネント間の関係、イベントリスナーなどの情報をすべてシリアライズし、HTML に埋め込みます。</li>
<li><strong>再開</strong>: クライアント側では、Qwik の非常に小さなランタイム（約 1KB）が、起動時にコンポーネントツリーを再構築したり、すべてのイベントを取り付けたりする必要はありません。グローバルイベントリスナーを通じて、ユーザーが特定のボタンをクリックしたときに、どの小さなコード片をダウンロードして実行すべきかを正確に判断できます。</li>
</ol>
<p>Qwik の目標は <strong>Instant-on</strong> な操作性です。サーバーの処理をもう一度「実行し直す」のではなく、サーバーが停止した場所から実行を「再開」します。</p>
<h2>結論</h2>
<p>Hydration はサーバーレンダリングとクライアント操作をつなぐ橋ですが、従来の実装では高コストで、ユーザー体験を損ねる可能性のあるプロセスです。モダンなフロントエンドフレームワークは、部分 Hydration（Astro）や再開可能性（Qwik）といった革新的なパターンによって、この「必要悪」から抜け出し、さらなる高性能と高速な操作性を目指しています。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[WebAssembly（WASM）はフロントエンド開発をどう変えているのか]]></title>
            <link>https://blog.m1ng.space/ja/posts/wasm/wasm-is-changing-frontend/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/wasm/wasm-is-changing-frontend/</guid>
            <pubDate>Sun, 30 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[ブラウザーで動く言語は、もはやJavaScriptだけではない。WebAssembly（WASM）はネイティブに近い性能を提供し、PhotoshopやFigmaのようなデスクトップ級の複雑なアプリケーションをWebへもたらしている。]]></description>
            <content:encoded><![CDATA[<h2>1. ブラウザーの「第二の言語」</h2>
<p>長い間、Webフロントエンド開発で使われる言語は事実上JavaScriptだけだった。JavaScriptは大きな成功を収めた一方、動的なインタープリター言語であるため、3Dレンダリング、動画のエンコードとデコード、複雑な計算といったCPU負荷の高い処理では、どうしても性能上の限界がある。</p>
<p>WebAssembly（略称WASM）は、この状況を打開するために登場した。JavaScriptを置き換えるものではなく、強力な補完役として、これまでにない性能と可能性をWebプラットフォームにもたらす。</p>
<h2>2. WebAssemblyとは何か？</h2>
<p>WebAssemblyは、スタックベースの仮想マシン向けに設計された<strong>バイナリ命令形式</strong>である。低レベルでアセンブリに似た言語だが、開発者が直接記述することを目的としてはいない。</p>
<p>その代わり、C、C++、Rust、Goなどの高水準言語の<strong>コンパイル先</strong>として設計されている。こうした高性能な言語でコードを書き、<code>.wasm</code>ファイルにコンパイルすれば、ブラウザー内でネイティブに近い速度で実行できる。</p>
<p><strong>重要な点：</strong></p>
<ul>
<li><strong>JavaScriptの代替ではない</strong>：WASMとJavaScriptは協力関係にある。</li>
<li><strong>コンパイル先である</strong>：C++やRustを書き、WASMへコンパイルする。</li>
<li><strong>高速、効率的、移植可能である</strong>：設計当初から性能を中心に据えている。</li>
</ul>
<h2>3. JavaScriptとWASMの協調モデル</h2>
<p>WASMモジュール自体はサンドボックス環境で動作し、DOMへ直接アクセスしたり、Web APIを呼び出したり、ネットワークリクエストを送ったりできない。これらの操作はすべて、JavaScriptが仲介する「接着剤」の層を通じて行う必要がある。</p>
<p>典型的な協調モデルは次のとおりだ：</p>
<ol>
<li><strong>JavaScriptが全体を取りまとめる</strong>：JSコードはアプリケーション全体のロジックを担い、ユーザーイベントを処理し、DOMを更新する。</li>
<li><strong>WASMが計算を担う</strong>：計算負荷の高い処理が必要になると、JSは<code>.wasm</code>モジュールからエクスポートされた関数を呼び出す。</li>
<li><strong>データをやり取りする</strong>：JSとWASMは、主に数値型や線形メモリのブロックを効率よく交換できる。</li>
</ol>
<p>JavaScriptを「マネージャー」、WebAssemblyを「熟練エンジニア」と考えると分かりやすい。マネージャーは連絡と調整を担当し、エンジニアは最も難しい技術課題を解決する。</p>
<h2>4. 実際の利用例</h2>
<p>WASMはもはや実験的な技術ではない。多くの一流Webアプリケーションが中核機能に採用している：</p>
<ul>
<li><strong>Figma</strong>：この人気オンラインデザインツールの中核レンダリングエンジンはC++で書かれ、WASMへコンパイルされている。そのため、滑らかなグラフィック編集を実現できる。</li>
<li><strong>Adobe Photoshop &amp; Lightroom</strong>：Adobeは主力デスクトップアプリケーションのC++コアコードをWASMでWebへ移植し、ブラウザー上で高機能なPhotoshopを利用できるようにした。</li>
<li><strong>Google Earth</strong>：新しいGoogle Earthはすべてブラウザー内で動作し、複雑な3D地球レンダリングをWASMが支えている。</li>
<li><strong>AutoCAD Web App</strong>：Autodeskは大規模なC++製CADエンジンをWASMへコンパイルし、完全なAutoCADをブラウザー内で動かせるようにした。</li>
</ul>
<p>これらの事例は、従来はデスクトップアプリケーションにしか実現できないと考えられていた複雑なソフトウェアを、WASMがすでにWebプラットフォームへ持ち込めることを示している。</p>
<h2>5. 未来：WASIとブラウザーの外側</h2>
<p>WASMの狙いはブラウザーだけにとどまらない。<strong>WASI（WebAssembly System Interface）</strong> は、ファイルシステムやネットワークへのアクセスなど、標準的なシステムレベルAPIをWASMに提供するための新しい標準である。</p>
<p>つまり将来、<code>.wasm</code>ファイルは汎用的でクロスプラットフォームかつ安全なバイナリ形式となり、サーバー（Dockerへの挑戦）、エッジコンピューティングのノード、IoTデバイスまで、あらゆる場所で動作するかもしれない。まさに「一度コンパイルすれば、どこでも動く」が実現する。</p>
<h2>結論</h2>
<p>WebAssemblyは、Webアプリケーションの能力の限界に対する私たちの認識を大きく変えている。JavaScriptは得意分野であるUI操作とアプリケーションロジックの取りまとめに集中し、性能の「天井」はRustやC++といったシステム言語からコンパイルされたWASMモジュールへ任せられる。フロントエンド開発者にとって、WASMの能力と適切な利用場面を理解することは、次世代の高性能Webアプリケーションを構築するうえで重要になる。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[View Transitions API でシームレスなページ遷移アニメーションを作る]]></title>
            <link>https://blog.m1ng.space/ja/posts/css/view-transitions-api/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/css/view-transitions-api/</guid>
            <pubDate>Mon, 22 Apr 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[ページ遷移時の「白いちらつき」は、長年ユーザー体験を損なう問題でした。現在はブラウザネイティブの View Transitions API によって、わずか数行のコードで映画のようなページ遷移を実現できます。]]></description>
            <content:encoded><![CDATA[<h2>1. ページ遷移における体験の隔たり</h2>
<p>Web 開発では、長い間ユーザー体験に関する次のようなジレンマがありました。</p>
<ul>
<li><strong>マルチページアプリケーション（MPA）</strong>: アーキテクチャは単純で安定していますが、ページを移動するたびに完全な読み込みが発生し、「白い画面」や「ちらつき」によって体験の連続性が失われます。</li>
<li><strong>シングルページアプリケーション（SPA）</strong>: フロントエンドルーティングによってリロードのない滑らかな体験を実現しますが、開発者は複雑な遷移アニメーション、状態管理、コード分割を手動で扱う必要があり、開発コストが高くなります。</li>
</ul>
<p>MPA の単純さを保ちながら、SPA の滑らかな遷移も得られる方法はないのでしょうか。View Transitions API は、まさにそのために生まれました。</p>
<h2>2. View Transitions API とは？</h2>
<p>View Transitions API はブラウザネイティブの API で、異なる二つの DOM 状態の間にアニメーション遷移を簡単に作成する仕組みを提供します。</p>
<p>基本的な処理の流れは非常に単純です。</p>
<ol>
<li>遷移を開始すると、API が現在のページ（古い状態）の「スナップショット」を撮ります。</li>
<li>次に JavaScript で DOM を新しい状態へ更新します。</li>
<li>API が新しいページ（新しい状態）の「スナップショット」も撮ります。</li>
<li>最後にブラウザが「古いスナップショット」と「新しいスナップショット」の間に、通常はフェードイン・フェードアウトによる滑らかなデフォルト遷移を作ります。</li>
</ol>
<p>これらはすべてブラウザの内部で効率よく処理されるため、必要なのは単純な関数を一つ呼び出すことだけです。</p>
<h2>3. 使い方</h2>
<p>シングルページアプリケーションで View Transitions を使うのは非常に簡単です。DOM の更新処理を <code>document.startViewTransition</code> 関数で包むだけです。</p>
<pre><code>// 假设你有一个更新页面内容的函数
async function updatePageContent(url) {
  const response = await fetch(url);
  const newHtml = await response.text();
  // 用新内容替换旧内容 (具体实现取决于你的架构)
  document.body.innerHTML = newHtml;
}

// 在导航链接的点击事件中调用
document.querySelector('a').addEventListener('click', (event) =&gt; {
  event.preventDefault();
  const url = event.target.href;

  // 检查浏览器是否支持
  if (!document.startViewTransition) {
    updatePageContent(url); // 不支持则直接更新
    return;
  }

  // 使用 View Transition
  document.startViewTransition(() =&gt; updatePageContent(url));
});
</code></pre>
<p>これだけで、ページ遷移にデフォルトのフェード効果が加わります。</p>
<h2>4. 遷移アニメーションのカスタマイズ</h2>
<p>デフォルトのフェード効果も優れていますが、この API の真価はカスタマイズ性にあります。<code>startViewTransition</code> の実行時、ブラウザは次の疑似要素を含む DOM 構造を作成します。</p>
<ul>
<li><code>::view-transition</code>: 遷移全体を含むルート要素。</li>
<li><code>::view-transition-old(root)</code>: 古いビューの「スナップショット」。</li>
<li><code>::view-transition-new(root)</code>: 新しいビューの「スナップショット」。</li>
</ul>
<p>CSS の <code>animation</code> でデフォルト効果を上書きできます。たとえば、次のようなスライドインアニメーションを実装できます。</p>
<pre><code>@keyframes slide-in {
  from { transform: translateX(100%); }
}

::view-transition-new(root) {
  animation: slide-in 0.5s ease-out;
}
</code></pre>
<h2>5. 要素間の「変形」：<code>view-transition-name</code></h2>
<p>この API で最も驚くべき機能は、二つのページにある <strong>異なる要素</strong> を <strong>同じオブジェクト</strong> として認識し、その間に滑らかな「変形」アニメーションを作れることです。</p>
<p>これは CSS プロパティ <code>view-transition-name</code> によって実現されます。</p>
<p><strong>ページ A（一覧ページ）:</strong></p>
<pre><code>&lt;img src="thumbnail.jpg" style="view-transition-name: hero-image;" /&gt;
</code></pre>
<p><strong>ページ B（詳細ページ）:</strong></p>
<pre><code>&lt;img src="full-size.jpg" style="view-transition-name: hero-image;" /&gt;
</code></pre>
<p>ページ A からページ B に移動すると、ブラウザは二つの要素の <code>view-transition-name</code> が同じであることを認識します。そして位置、サイズ、形状の差を自動的に計算し、単純なフェードではなく滑らかな遷移アニメーションを生成します。画像やカードなどの要素の遷移に特に適しています。</p>
<h2>結論</h2>
<p>View Transitions API は、待望されていたネイティブの遷移機能を Web にもたらします。従来は複雑な JavaScript アニメーションライブラリが必要だったインタラクションを大幅に単純化し、映画のように滑らかなアプリケーション体験をかつてないほど簡単に作れるようにします。Astro や Nuxt などのフレームワークへの統合が進み、将来マルチページアプリケーションにも普及すれば、モダン Web 開発者の標準スキルの一つになるでしょう。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[React Server Components を深く理解する]]></title>
            <link>https://blog.m1ng.space/ja/posts/react/deep-dive-into-rsc/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/react/deep-dive-into-rsc/</guid>
            <pubDate>Fri, 15 Mar 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[React Server Components（RSC）は、近年の React における最も重要なパラダイムシフトの一つです。本稿では、その中核概念、解決する問題、そしてアプリケーション構築の方法をどう変えるのかを詳しく解説します。]]></description>
            <content:encoded><![CDATA[<h2>1. React Server Components（RSC）とは？</h2>
<p>React Server Components（RSC）は、<strong>ビルド時またはサーバー上</strong>でレンダリングされる新しい種類の React コンポーネントです。クライアントのブラウザでレンダリングされる従来のコンポーネント（現在は「Client Components」と呼ばれます）とは異なり、RSC のコードがクライアントへ送信されることはありません。ブラウザが受け取るのは、レンダリング済みの HTML または特殊なストリーミング形式だけです。</p>
<p>これは、React が純粋なクライアントサイドライブラリから、サーバーとクライアントの間でシームレスに動作するフルスタックフレームワークへと進化したことを示します。</p>
<h2>2. RSC はどのような問題を解決するのか？</h2>
<p>RSC は主に、次のような中心的な課題を解決するために登場しました。</p>
<ul>
<li><strong>巨大な JavaScript バンドルサイズ</strong>: 従来の React アプリケーションは、直接操作しないコンポーネントも含め、すべてのコンポーネントの JS コードをバンドルしてクライアントへ送るため、初期読み込みが遅くなります。RSC を使えば、テキスト、レイアウト、データ表示など多くのコンポーネントをサーバー側に残し、<strong>JS サイズをゼロ</strong>にできます。</li>
<li><strong>リクエストウォーターフォール（Request Waterfalls）</strong>: クライアントでデータを取得する典型的な流れは、コンポーネントをレンダリング -&gt; <code>useEffect</code> -&gt; リクエストを送信 -&gt; データを待機 -&gt; 再レンダリング、というものです。コンポーネントのネストが深いとリクエストウォーターフォールが発生し、ページの表示が遅くなります。RSC はサーバーで直接 <code>async/await</code> によるデータ取得を行い、データとコンポーネントを一緒にクライアントへストリーミングできるため、この問題を根本から解決します。</li>
<li><strong>バックエンド資源への直接アクセス</strong>: RSC は Node.js などのサーバー環境で実行されます。そのため、クライアント向けに追加の API エンドポイントを公開することなく、データベース、ファイルシステム、内部 API へ直接かつ安全にアクセスできます。</li>
</ul>
<h2>3. Server Components と Client Components</h2>
<p>両者の違いを理解することが、RSC を使いこなす鍵です。</p>
<table>
<thead>
<tr>
<th>特性</th>
<th>Server Components（サーバーコンポーネント）</th>
<th>Client Components（クライアントコンポーネント）</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>実行環境</strong></td>
<td>サーバー（Node.js など）</td>
<td>クライアント（ブラウザ）</td>
</tr>
<tr>
<td><strong>クライアントへ送信する JS</strong></td>
<td>なし</td>
<td>あり</td>
</tr>
<tr>
<td><strong>状態（State）</strong></td>
<td>非対応（例：<code>useState</code>）</td>
<td>対応</td>
</tr>
<tr>
<td><strong>ライフサイクル/Hooks</strong></td>
<td>非対応（例：<code>useEffect</code>）</td>
<td>対応</td>
</tr>
<tr>
<td><strong>操作（Events）</strong></td>
<td>非対応（例：<code>onClick</code>）</td>
<td>対応</td>
</tr>
<tr>
<td><strong>データ取得</strong></td>
<td><code>async/await</code> に対応</td>
<td><code>useEffect</code> またはデータ取得ライブラリを使用</td>
</tr>
<tr>
<td><strong>インポート規則</strong></td>
<td>Client Components をインポートできない</td>
<td>Server Components をインポートできる（<code>children</code> または <code>prop</code> として）</td>
</tr>
</tbody>
</table>
<p><strong>経験則</strong>: デフォルトではすべてのコンポーネントを Server Components と考えます。コンポーネントで <code>useState</code> や <code>useEffect</code> を使う、または <code>onClick</code> などのユーザーイベントを処理する必要がある場合にだけ、ファイルの先頭へ <code>"use client";</code> ディレクティブを追加して Client Component として指定します。</p>
<h2>4. 両者はどのように連携するのか？</h2>
<p>現代の React アプリケーションは、両者を組み合わせたものになります。たとえば、ブログ記事のページでは次のように構成できます。</p>
<ul>
<li><code>PageLayout</code>（Server Component）: 全体のレイアウトを担当します。</li>
<li><code>ArticleContent</code>（Server Component）: データベースまたは Markdown ファイルから記事データを取得してレンダリングします。</li>
<li><code>LikeButton</code>（Client Component）: <code>useState</code> と <code>onClick</code> イベントを持ち、「いいね」の操作を処理します。</li>
<li><code>Comments</code>（Client Component）: コメントを取得して表示し、フォーム送信などの操作を扱います。</li>
</ul>
<p>Server Components はサーバー側で Client Components のための「場所」を確保し、最終的にブラウザ上で両者をシームレスに組み合わせられます。</p>
<h2>まとめ</h2>
<p>React Server Components は大きなパラダイムシフトです。React の能力をブラウザからサーバーへ拡張し、明確なパフォーマンス上の利点と、より優れた開発体験をもたらします。新しいメンタルモデルは必要になりますが、Next.js App Router などのフレームワークで実践されることで、RSC は高性能でスケーラブルな Web アプリケーションを構築する新たな標準になりつつあります。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[process.env.UNDEFINEDに別れを：型安全な環境変数をプロジェクトに導入する]]></title>
            <link>https://blog.m1ng.space/ja/posts/typescript/typesafe-environment-variables/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/typescript/typesafe-environment-variables/</guid>
            <pubDate>Sun, 25 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[環境変数の欠落や形式の誤りは、実行時バグのよくある原因だ。Zodなどの検証ライブラリを使えば、起動時にすべての環境変数が存在し、正しい型であることを確認して、この種の問題を根本から防げる。]]></description>
            <content:encoded><![CDATA[<h2>1. <code>process.env</code>の「落とし穴」</h2>
<p>Node.jsアプリケーションでは、<code>process.env</code>を通じて環境変数へアクセスする。簡単で有効な仕組みだが、<strong>型安全ではない</strong>という本質的な問題がある。</p>
<p><code>process.env</code>オブジェクトの値は、<code>string</code>か<code>undefined</code>のどちらかである。そのため、よくある問題がいくつか生じる：</p>
<ul>
<li><strong>予期しない<code>undefined</code></strong>：<code>.env</code>ファイルやサーバーに変数を設定し忘れると、実行時の<code>process.env.MY_VAR</code>は<code>undefined</code>になる。これがコードの深い部分で<code>TypeError</code>を引き起こすことがある。</li>
<li><strong>型の不一致</strong>：ポート番号を<code>number</code>型として扱いたくても、<code>process.env.PORT</code>は常に文字列である。使用する場所ごとに手動で<code>parseInt</code>を呼ぶ必要がある。</li>
<li><strong>検証ロジックの分散</strong>：<code>const port = process.env.PORT || 3000;</code>のような防御的コードを各所に書きがちで、環境変数の管理が散らかってしまう。</li>
</ul>
<h2>2. 中心原則：起動時に失敗する（Fail-Fast）</h2>
<p>環境変数のような重要な設定では、ベストプラクティスは <strong>「起動時に失敗する」（Fail-Fast）</strong> ことである。</p>
<p>つまりアプリケーションは、起動直後に必要な環境変数がすべて用意され、形式も正しいかを確認するべきだ。問題があれば、設定ミスによって将来の予測できない時点でクラッシュするのではなく、すぐにエラーを投げて停止する。</p>
<p>これにより、ユーザーがアクセスしたときではなく、デプロイや開発の時点で設定の問題を直ちに発見できる。</p>
<h2>3. Zodで型安全な検証を実現する</h2>
<p>ZodはTypeScriptを第一に設計されたスキーマ宣言・検証ライブラリである。環境変数の型安全性という問題を解決するのに適している。</p>
<p>戦略は次のとおりだ：</p>
<ol>
<li>すべての環境変数に対するZodスキーマを定義する。</li>
<li>アプリケーションの起動時に、そのスキーマで<code>process.env</code>を解析する。</li>
<li>解析に失敗した、つまり検証を通らなかった場合は、Zodがエラーを投げ、アプリケーションの起動も失敗する。</li>
<li>解析に成功すれば、完全に型付けされたオブジェクトを取得し、アプリケーション全体で利用する。</li>
</ol>
<h4>実装例</h4>
<p>まずZodをインストールする：<code>pnpm add zod</code></p>
<p>次に、<code>src/env.ts</code>など、環境変数を扱う専用ファイルを作成する：</p>
<pre><code>// src/env.ts
import { z } from 'zod';

// 1. 定义 Schema
const envSchema = z.object({
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  DATABASE_URL: z.string().min(1, 'DATABASE_URL is required.'),
  PORT: z.coerce.number().int().positive().default(3000),
  // z.coerce 会尝试将字符串转换为数字
});

// 2. 解析和导出
// .parse 会在验证失败时抛出错误，实现 "Fail-Fast"
export const env = envSchema.parse(process.env);
</code></pre>
<p>これでアプリケーション内のどこからでも、<code>src/env</code>から<code>env</code>オブジェクトをインポートできる。</p>
<pre><code>// src/server.ts
import { env } from './env'; // 导入经过验证和类型化的 env 对象

// env.PORT 的类型是 `number`，而不是 `string | undefined`
const port = env.PORT;

// env.NODE_ENV 的类型是 'development' | 'production' | 'test'
if (env.NODE_ENV === 'development') {
  console.log('Running in development mode');
}

// 如果 DATABASE_URL 未设置，应用在启动时就已经崩溃了，
// 所以在这里我们可以放心地认为它是存在的，并且类型是 `string`。
connectToDatabase(env.DATABASE_URL);
</code></pre>
<h2>4. 得られる利点</h2>
<p>このパターンには、すぐに実感できる利点がある：</p>
<ul>
<li><strong>完全な型安全性</strong>：コードで<code>env.PORT</code>へアクセスするとき、TypeScriptはそれが<code>number</code>だと把握している。</li>
<li><strong>ドキュメントと検証の集約</strong>：<code>env.ts</code>ファイル自体が環境変数の信頼できるドキュメントとなり、すべての検証ロジックも一か所にまとまる。</li>
<li><strong>信頼できる実行環境</strong>：環境変数のタイプミス、欠落、形式の誤りによる実行時バグを防ぐ。</li>
<li><strong>Fail-Fast</strong>：設定上の問題をデプロイや開発の最初の段階で発見できる。</li>
</ul>
<h2>結論</h2>
<p>環境変数の検証をアプリケーションの起動時へ前倒しし、Zodのようなツールで型安全性を保証することは、費用対効果の非常に高いエンジニアリング手法である。アプリケーションの堅牢性と開発者の自信を大きく高められるため、現代のTypeScriptプロジェクトに欠かせない要素だ。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[Vue 3.4アップデート：より簡潔なv-bind記法とさらなる性能向上]]></title>
            <link>https://blog.m1ng.space/ja/posts/vue/vue-3-4-v-bind-updates/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/vue/vue-3-4-v-bind-updates/</guid>
            <pubDate>Mon, 15 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Vue 3.4「🏀 Slam Dunk」が正式リリースされた。より効率的に書き直されたリアクティブシステムと安定版defineModel APIにより、双方向バインディングを持つコンポーネントの開発体験が大きく向上する。]]></description>
            <content:encoded><![CDATA[<h2>1. Vue 3.4「Slam Dunk」の概要</h2>
<p>2024年初め、Vueチームはコードネーム「Slam Dunk」と呼ばれるバージョン3.4をリリースした。3.0ほど抜本的なバージョンではないものの、<strong>内部の性能最適化</strong>と<strong>開発者体験の向上</strong>という二つの重要な領域で大きな改善をもたらした。</p>
<p>なかでも注目すべき変更は、リアクティブシステムの書き直し、安定版となった<code>defineModel</code> API、そしてより簡潔な<code>v-bind</code>構文である。</p>
<h2>2. リアクティブシステムの再構築</h2>
<p>Vue 3.4では、中核となるリアクティブシステムが大幅に書き直された。主な目的は、<code>computed</code>による算出プロパティの効率を高めることにある。</p>
<p>従来のバージョンでは、依存先が実際には変化していなくても、算出プロパティが不要に再計算されることがあった。新しいバージョンでは、より賢い依存関係の追跡によって、本当に必要なときだけ計算を実行し、不要なコンポーネントの再レンダリングを減らしている。</p>
<p>多くの開発者にとって、これは「無料の昼食」だ。コードを一切変更しなくても、3.4へアップグレードするだけで性能向上を自動的に得られる。</p>
<h2>3. <code>defineModel</code>：コンポーネントの双方向バインディングを美しく</h2>
<p>3.4より前は、コンポーネントに<code>v-model</code>のような双方向バインディングを実装するために、かなりの定型コードが必要だった：</p>
<p><strong>以前 👎：</strong></p>
<pre><code>&lt;script setup&gt;
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])

// 通常需要一个计算属性来包装
const value = computed({
  get: () =&gt; props.modelValue,
  set: (val) =&gt; emit('update:modelValue', val)
})
&lt;/script&gt;

&lt;template&gt;
  &lt;input v-model="value" /&gt;
&lt;/template&gt;
</code></pre>
<p>Vue 3.4では、<code>defineModel</code> APIが実験段階を終えて正式な安定版になった。今では、同じ機能を一行のコードで実現できる：</p>
<p><strong>現在（Vue 3.4）👍：</strong></p>
<pre><code>&lt;script setup&gt;
const model = defineModel()
&lt;/script&gt;

&lt;template&gt;
  &lt;input v-model="model" /&gt;
&lt;/template&gt;
</code></pre>
<p><code>defineModel</code>マクロは<code>modelValue</code> propと<code>update:modelValue</code>イベントを自動的に登録し、直接読み書きできる<code>ref</code>を返す。これにより、<code>v-model</code>に対応するコンポーネントの開発が大幅に簡単になる。</p>
<h2>4. 同名属性に対する<code>v-bind</code>の省略記法</h2>
<p>開発体験を高めるもう一つのシンタックスシュガーが、同名の場合に使える<code>v-bind</code>の省略記法だ。コンポーネントへ渡すpropと<code>&lt;script setup&gt;</code>で定義した変数が同じ名前なら、属性値を省略できるようになった。</p>
<p><strong>以前 👎：</strong></p>
<pre><code>&lt;script setup&gt;
const id = 'my-id'
const title = 'Hello Vue'
&lt;/script&gt;

&lt;template&gt;
  &lt;MyComponent :id="id" :title="title" /&gt;
&lt;/template&gt;
</code></pre>
<p><strong>現在（Vue 3.4）👍：</strong></p>
<pre><code>&lt;script setup&gt;
const id = 'my-id'
const title = 'Hello Vue'
&lt;/script&gt;

&lt;template&gt;
  &lt;MyComponent :id :title /&gt;
&lt;/template&gt;
</code></pre>
<p>この小さな変更によって、テンプレートのコードがよりすっきりと読みやすくなる。</p>
<h2>結論</h2>
<p>Vue 3.4は堅実なアップデートである。低レベルの性能最適化と高レベルAPIの簡素化により、「プログレッシブ」なフレームワークというVueの理念をさらに強固にした。大規模アプリケーションには強力な性能を保証し、日々の開発には具体的な利便性をもたらす。特に<code>defineModel</code>の安定化は、コンポーネントのカプセル化に長く存在した課題を解決したもので、今回の更新で最も評価すべき点である。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[さようならRome、こんにちはBiome：オールインワンフロントエンドツールチェーンの新たな選択肢]]></title>
            <link>https://blog.m1ng.space/ja/posts/build-tools/intro-to-biome/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/build-tools/intro-to-biome/</guid>
            <pubDate>Fri, 10 Nov 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Romeツールチェーンの構想は、かつて多くの開発者を魅了しました。商業化の失敗後、コミュニティはBiomeの名でその志を継承しました。Rustで書かれたこのオールインワンツールチェーンは、私たちの道具箱の新たな一員になれるでしょうか。]]></description>
            <content:encoded><![CDATA[<h2>1. フロントエンド開発の「ツール疲れ」</h2>
<p>モダンなフロントエンド開発では、プロジェクトを円滑に動かすために、通常は複雑なツールの組み合わせが必要です。</p>
<ul>
<li><strong>Linter</strong>：ESLintはJavaScript/TypeScriptコードの品質を検査します。</li>
<li><strong>Formatter</strong>：Prettierはコードスタイルを統一します。</li>
<li><strong>Compiler</strong>：BabelまたはTypeScript（tsc）はコードを変換します。</li>
<li><strong>Bundler</strong>：Webpack、Rollup、Viteはコードをバンドルします。</li>
</ul>
<p>これらのツールの設定、プラグイン、バージョン、相互作用を管理すること自体が大きな仕事です。これがいわゆる「ツール疲れ」です。コミュニティは長年にわたり、1つのツールですべての問題を解決する「オールインワンツールチェーン」の可能性を模索してきました。</p>
<h2>2. Romeの構想とBiomeの誕生</h2>
<p>Romeは、Facebookの元従業員でBabelの作者でもあるSebastian McKenzieが始めた野心的なプロジェクトで、フロントエンドツールチェーン全体をTypeScriptで書き直すことを目指していました。その構想は、設定不要で高性能な統合ツールを提供することでした。しかし、長年の開発と商業化の試みを経た後、Rome Labsは2023年に事業停止を発表しました。</p>
<p>幸い、Romeのコアコードはオープンソースでした。コミュニティはすぐに動き、<strong>Biome</strong>という名前のフォークを作成し、専用のコミュニティ組織が保守することで、Romeの当初の構想を継承し実現しようとしています。</p>
<h2>3. Biomeとは？</h2>
<p>BiomeはRustで書き直された高性能なフロントエンドツールチェーンです。ESLintやPrettierなど一連の独立したツールに代わる、統合された非常に高速な開発体験を提供することを目指しています。</p>
<p>2023年末の時点で、Biomeの中核機能は主に<strong>Linter</strong>と<strong>Formatter</strong>に集中しており、どちらでも驚くべき実力を示していました。</p>
<h4>主な利点：</h4>
<ul>
<li><strong>圧倒的な性能</strong>：Rustのおかげで、BiomeはJavaScriptで書かれたESLintやPrettierよりはるかに高速に動作します。大規模なコードベースでは、性能向上が1桁違うこともあります。</li>
<li><strong>統一された設定</strong>：1つの<code>biome.json</code>ファイルだけで、すべてのツールの動作を管理でき、各所に散らばった<code>.eslintrc</code>、<code>.prettierrc</code>、<code>.editorconfig</code>から解放されます。</li>
<li><strong>詳細な診断情報</strong>：BiomeのLinterはエラーを指摘するだけでなく、非常に詳しいコンテキストと修正提案を提供し、開発者が問題の根本原因を理解できるようにします。</li>
<li><strong>Prettierとの互換性</strong>：BiomeのフォーマッターはPrettierのルールの95%以上との互換性を目指しており、Prettierからの移行コストを非常に低く抑えます。</li>
</ul>
<h2>4. クイックスタート</h2>
<p><code>npx</code>を使って、プロジェクト内ですぐにBiomeを試せます。</p>
<pre><code># 检查当前项目中的代码问题
npx @biomejs/biome check ./src

# 自动修复可修复的 lint 问题
npx @biomejs/biome check --apply ./src

# 格式化代码
npx @biomejs/biome format --write ./src
</code></pre>
<p><code>biome.json</code>ファイルを作成すると、ルールと設定をカスタマイズできます。</p>
<pre><code>{
  "$schema": "https://biomejs.dev/schemas/1.4.1/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}
</code></pre>
<h2>5. 今後の展望</h2>
<p>Biomeのロードマップは非常に明確です。LinterとFormatterを安定させた上で、Compiler、Bundler、Test Runnerなどの機能を段階的に実装し、最終的に名実ともに「オールインワン」のツールチェーンになることを目指しています。</p>
<p>Biomeはまだ若いものの、優れた性能、コミュニティ主導のオープンなモデル、開発者体験への注力によって、フロントエンドツール分野で無視できない新勢力となっています。ツールスタックを簡素化し、開発効率を高めたいチームにとって、Biomeは非常に魅力的な将来の選択肢です。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[Bun 1.0正式リリース：Node.jsに挑むオールインワンランタイム]]></title>
            <link>https://blog.m1ng.space/ja/posts/build-tools/bun-1-0-release/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/build-tools/bun-1-0-release/</guid>
            <pubDate>Sun, 10 Sep 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[2023年9月、Bun 1.0のリリースはJavaScriptコミュニティに波紋を広げました。ゼロから構築されたこのJavaScriptツールキットは、驚異的な速度と「オールインワン」設計を武器に、Node.jsの支配的地位へ正式に挑みます。]]></description>
            <content:encoded><![CDATA[<h2>1. JavaScriptランタイムの新たな競争相手</h2>
<p>10年以上にわたり、Node.jsはサーバーサイドJavaScriptの代名詞でした。DenoがセキュリティやモダンなAPIについて新しい考え方を示したものの、Node.jsの地位が本当に揺らいだようには見えませんでした。しかし2023年9月、Bun 1.0が正式にリリースされたことで、状況は変わるかもしれません。</p>
<p>Bunは単なる別のJavaScriptランタイムではありません。ゼロから設計された、パフォーマンス重視の「オールインワン」ツールキットであり、開発からデプロイまでのライフサイクル全体を担うことを目指しています。</p>
<h2>2. Bunの核心：速度、速度、そして速度</h2>
<p>Bunの第一の設計目標はパフォーマンスです。そのために、いくつかの独自な技術選択を行っています。</p>
<ul>
<li><strong>Zig言語</strong>：Bunの基盤はZigで書かれています。Zigはパフォーマンスとメモリ制御を重視するモダンなシステムプログラミング言語であり、低レベルの細部まで徹底的に最適化できます。</li>
<li><strong>JavaScriptCoreエンジン</strong>：GoogleのV8エンジンを使うNode.jsやDenoとは異なり、BunはAppleのJavaScriptCore（JSC）エンジンを選びました。JSCは起動が速く、一般にメモリ消費も少ないことで知られています。</li>
</ul>
<p>こうした選択により、Bunはスクリプトの起動、<code>bun install</code>の速度、組み込みAPIの実行効率で驚異的なパフォーマンスを示しています。</p>
<h2>3. ランタイムだけではない</h2>
<p>Bunの「オールインワン」設計も大きな特徴です。単なる<code>node</code>コマンドの代替ではなく、次の機能も内蔵しています。</p>
<ul>
<li><strong>パッケージマネージャー</strong>：<code>bun install</code>は<code>npm install</code>の数倍、場合によっては数十倍高速です。グローバルモジュールキャッシュと効率的な依存関係解決アルゴリズムを使い、インストール時間を大幅に短縮します。</li>
<li><strong>ビルドツール／バンドラー</strong>：Bunは高性能なバンドラーを内蔵し、プロジェクトを実行ファイルやブラウザー向けコードへ直接まとめられます。その性能はesbuildに匹敵します。</li>
<li><strong>ネイティブトランスパイラー</strong>：TypeScript（<code>.ts</code>）やJSX（<code>.jsx</code>、<code>.tsx</code>）ファイルを、<code>tsc</code>や<code>babel</code>を事前に設定せず直接実行できます。Bunは実行時にそれらを非常に高速で変換します。</li>
<li><strong>テストランナー</strong>：<code>bun test</code>はJestとの高い互換性を持つテスト環境を提供しながら、はるかに高速に動作します。</li>
</ul>
<p>つまり新しいプロジェクトでは、<code>bun</code>という1つのツールをインストールするだけで、開発、テスト、バンドルの全工程をこなせる可能性があります。</p>
<h2>4. Node.jsとの互換性</h2>
<p>移行を容易にするため、BunチームはNode.js APIとの互換性の実現に多大な労力を注いでいます。<code>node_modules</code>の解決、CommonJS（<code>require</code>）とESM（<code>import</code>）モジュール、さらに<code>fs</code>、<code>path</code>、<code>http</code>など多数のNode.jsコアモジュールをサポートしています。</p>
<p>既存のNode.jsプロジェクトの多くは、理論上<code>bun</code>でそのまま実行し、すぐにパフォーマンス向上の恩恵を受けられます。</p>
<h2>5. 課題と未来</h2>
<p>Bunの登場は、フロントエンド界で長く続いてきた「小さな専用ツールを組み合わせる」という思想に挑戦しています。「大きく全部入り」のモデルは、比類のない利便性とすぐに使える高性能をもたらす一方で、柔軟性の一部を犠牲にする可能性もあります。</p>
<p>Node.jsには非常に巨大で成熟したエコシステムがあり、Bunが短期間で追いつくのは困難です。しかしBun 1.0のリリースは、本番環境に対応する準備が整ったことを示しました。その驚異的な性能と統合された開発体験は、新規プロジェクトや究極の効率を求めるチームにとって抗いがたい魅力を持っています。</p>
<p>Bunが将来Node.jsの地位を覆せるかどうかにかかわらず、その登場はすでにJavaScriptツールチェーンの発展に新たな活力を注ぎ、新しいパフォーマンス基準を打ち立てています。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[ネイティブCSS Nestingがついに登場！]]></title>
            <link>https://blog.m1ng.space/ja/posts/css/native-css-nesting/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/css/native-css-nesting/</guid>
            <pubDate>Fri, 01 Sep 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[10年待ちました！Sass/Lessの中核機能であるセレクターのネストが、ついに主要ブラウザーでネイティブにサポートされました。プリプロセッサーに別れを告げ、より簡潔で直感的なCSSの書き方を迎えましょう。]]></description>
            <content:encoded><![CDATA[<h2>1. 10年間使ってきた「非公式」機能</h2>
<p>数年前にフロントエンドコードを書いたことがあれば、SassやLessをよく知っているはずです。これらのCSSプリプロセッサーには、ほぼすべての開発者に愛される機能があります。<strong>セレクターのネスト（Nesting）</strong> です。HTMLを書くように子セレクターのルールを親セレクターの内側へ記述でき、コードの可読性と構成を大きく改善します。</p>
<pre><code>// Sass 语法
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}
</code></pre>
<p>長年、この構文をブラウザーが理解できる通常のCSSへコンパイルするため、ビルドツールに頼ってきました。しかし今、状況は変わりました。</p>
<h2>2. ネイティブCSS Nestingの登場</h2>
<p>2023年初頭から、主要ブラウザーのChrome、Safari、Firefoxが相次いでネイティブのCSS Nesting Moduleへの対応を発表しました。つまり、前処理を一切せずに<code>.css</code>ファイルへ直接ネストしたルールを書けます。</p>
<p>上の例はネイティブCSSで次のように書けます。</p>
<pre><code>/* 原生 CSS 语法 */
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}
</code></pre>
<p>そうです。Sassとまったく同じように見えます。</p>
<h2>3. <code>&amp;</code>の重要な役割</h2>
<p>プリプロセッサーと同じく、<code>&amp;</code>記号はネイティブのネストでも重要な役割を果たし、親セレクターを表します。疑似クラス、疑似要素、組み合わせセレクターを扱うときに特に便利です。</p>
<pre><code>.card {
  background: white;
  border-radius: 8px;

  /* &amp; 代表 .card */
  &amp;:hover {
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  }

  /* &amp; 代表 .card，组合成 .card.dark-mode */
  &amp;.dark-mode {
    background: #333;
  }

  /* &amp; 代表 .card，组合成 .card &gt; .header */
  &gt; .header {
    font-weight: bold;
  }
}
</code></pre>
<h2>4. Sassとの小さいが重要な違い</h2>
<p>Sassでは、<code>.card { .title { ... } }</code>のようにクラスセレクターを直接ネストできます。ネイティブCSS Nestingの初期仕様ではこれは認められず、ネストしたルールはすべて<code>&amp;</code>、<code>&gt;</code>、<code>+</code>、<code>~</code>などの記号で始める必要がありました。</p>
<p>最新仕様ではこの制限が緩和され、<code>article { h1 { ... } }</code>のように型セレクターを直接ネストできるようになりました。それでもクラスセレクターをネストするときは、意図を明確にして曖昧さを避けるため、<code>&amp;</code>を使うのがベストプラクティスです。</p>
<pre><code>/* 推荐写法 */
.article {
  &amp; .author-name {
    font-style: italic;
  }
}

/* 不推荐的写法 (在某些早期实现或严格解析器中可能无效) */
.article {
  .author-name {
    font-style: italic;
  }
}
</code></pre>
<p><code>&amp;</code>を使うと、<code>.author-name</code>が<code>.article</code>の子孫であることを明確に表せます。</p>
<h2>5. ブラウザー対応と今後</h2>
<p>2023年9月時点で、主要なモダンブラウザー（Chrome 112+、Safari 16.5+、Firefox 117+）はすべてCSS Nestingに対応しています。つまり、本番環境でも段階的に使い始められます。</p>
<p>ネイティブCSS Nestingの登場は、Webプラットフォーム自体の進化における新たな重要な節目です。ビルドツールへの依存を減らし、CSS自体をより強力で表現豊かにすると同時に、フロントエンドを学び始めた開発者も、より直感的にスタイルコードを書いて理解できるようになります。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[Utility-First CSS の台頭：Tailwind CSS を例に]]></title>
            <link>https://blog.m1ng.space/ja/posts/css/the-rise-of-utility-first/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/css/the-rise-of-utility-first/</guid>
            <pubDate>Sun, 20 Aug 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[BEM や CSS-in-JS の悩みから解放されるのでしょうか。Utility-First CSS の思想と、その代表的なフレームワークである Tailwind CSS は、近年フロントエンドコミュニティを席巻しています。その魅力はどこにあるのでしょうか。]]></description>
            <content:encoded><![CDATA[<h2>1. 従来の CSS 方法論が抱える課題</h2>
<p>Utility-First が登場する以前から、スタイルを整理するための優れた CSS 方法論は数多く存在していました。たとえば次のようなものです。</p>
<ul>
<li><strong>BEM (Block, Element, Modifier)</strong>: <code>block__element--modifier</code> という命名規則によって、スタイルの独立性と保守性を確保します。</li>
<li><strong>OOCSS (Object-Oriented CSS)</strong>: 構造と見た目を分離し、コンテナとコンテンツも分離することを提唱します。</li>
<li><strong>CSS-in-JS</strong>: CSS を JavaScript コンポーネント内に直接記述し、コンポーネント単位でスタイルをカプセル化します。</li>
</ul>
<p>これらの方法は CSS のグローバル汚染やコード整理の問題をある程度解決しましたが、多くの場合、新たな問題も生みました。無数の class を命名するための思考負荷、ファイルを切り替える煩わしさ、そして CSS-in-JS がもたらす可能性のある実行時コストです。</p>
<h2>2. Utility-First とは？</h2>
<p>Utility-First（ユーティリティ優先）とは、<strong>単一の目的を持ち、名前が変わらないユーティリティクラス</strong>を一式用意し、それらを組み合わせて複雑な UI を構築するという CSS の考え方です。</p>
<p>たとえば <code>.card</code> クラスを作り、CSS ファイル内で <code>display</code>、<code>padding</code>、<code>box-shadow</code> を定義するのではなく、
HTML に直接次のように記述します。</p>
<pre><code>&lt;div class="block p-6 rounded-lg shadow-lg bg-white"&gt;
  
&lt;/div&gt;
</code></pre>
<p>ここで使われている <code>block</code>、<code>p-6</code>、<code>rounded-lg</code> などはユーティリティクラスで、それぞれが一つの小さな役割だけを担います。</p>
<h2>3. Tailwind CSS：Utility-First の代表例</h2>
<p>Tailwind CSS は現在最も人気のある Utility-First CSS フレームワークです。一般的な CSS プロパティをほぼすべて網羅する、非常に詳細なユーティリティクラス群を提供します。</p>
<p><strong>主な利点:</strong></p>
<ul>
<li><strong>非常に高速な開発</strong>: HTML ファイルからほとんど離れる必要がありません。アトミッククラスを組み合わせることで、あらゆるデザインを素早く構築でき、プロトタイピングと開発の効率が大幅に向上します。</li>
<li><strong>デザインシステムの強制</strong>: すべてのスタイル（色、余白、文字サイズ）が事前定義された設定（theme）に由来するため、チーム全体で UI の一貫性を保ちやすく、「マジックナンバー」も避けられます。</li>
<li><strong>命名の悩みが不要</strong>: 「コンピュータサイエンスの二大難問は、キャッシュの無効化と命名である。」Tailwind を使えば、CSS クラスの命名にほとんど悩まなくて済みます。</li>
<li><strong>優れたパフォーマンス</strong>: 本番ビルド時に Tailwind はファイルを走査し、PurgeCSS（または内蔵 JIT エンジン）によって未使用の CSS クラスをすべて削除するため、最終的な CSS ファイルは通常非常に小さくなります。</li>
</ul>
<h2>4. 「クラス名地獄」？—— 欠点を見る別の視点</h2>
<p>Tailwind に対する最も一般的な批判は、HTML が非常に肥大化して読みにくくなり、「インラインスタイル」の時代に戻ったように見えることです。</p>
<pre><code>&lt;button class="py-2 px-4 font-semibold rounded-lg shadow-md text-white bg-blue-500 hover:bg-blue-700"&gt;
  Click me
&lt;/button&gt;
</code></pre>
<p>確かに慣れが必要です。しかし支持者は次のように考えます。</p>
<ol>
<li>スタイルと構造はもともと密接に結び付いているため、同じ場所に置く方がむしろ保守しやすい。</li>
<li>React や Vue のコンポーネントなど、再利用可能なコンポーネントとして切り出せば、この「混乱」を内部に閉じ込められる。</li>
</ol>
<p>再利用したいスタイルの組み合わせに対して、Tailwind は <code>@apply</code> ディレクティブを提供しています。</p>
<pre><code>/* in your css file */
.btn-primary {
  @apply py-2 px-4 font-semibold rounded-lg shadow-md text-white bg-blue-500 hover:bg-blue-700;
}
</code></pre>
<p>これで HTML 内から <code>.btn-primary</code> を使用できます。ただし Tailwind 公式は、再利用の問題をコンポーネント化によって解決することをより推奨しています。</p>
<h2>結論</h2>
<p>Utility-First と Tailwind CSS の成功は、フロントエンド開発における「関心の分離」の考え方が、言語の分離（HTML/CSS/JS）からコンポーネントの分離へ移ったことを示しています。一見「原始的」に見える方法で、モダン Web 開発の多くの実際的な問題を解決し、効率的で一貫性があり、高性能な UI への近道を開発者に提供します。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[次世代のE2Eテストツール：Playwright入門ガイド]]></title>
            <link>https://blog.m1ng.space/ja/posts/testing/intro-to-playwright/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/testing/intro-to-playwright/</guid>
            <pubDate>Thu, 20 Jul 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[不安定なE2Eテストにうんざりしていないだろうか。Microsoft製のPlaywrightは、クロスブラウザー対応、自動待機、強力なデバッグツールによって、テスト自動化の新しい基準になりつつある。]]></description>
            <content:encoded><![CDATA[<h2>1. エンドツーエンドテストの課題</h2>
<p>エンドツーエンド（E2E）テストは、アプリケーションの品質を守る最後の防衛線である。クリック、入力、移動といった実際のユーザー操作を再現し、アプリケーション全体の流れが円滑に動くかを検証する。しかしE2Eテストは、「壊れやすい」「不安定」としても知られている：</p>
<ul>
<li><strong>非同期の問題</strong>：スクリプトの実行時にDOM要素の読み込みが終わっておらず、テストが失敗することがある。開発者は大量の<code>wait</code>や<code>sleep</code>を手動で追加する必要があり、テストの信頼性が下がる。</li>
<li><strong>クロスブラウザー互換性</strong>：主要ブラウザー（Chrome、Firefox、Safari）のすべてでテストを安定して動かすことは大きな課題である。</li>
<li><strong>デバッグの難しさ</strong>：CI/CD環境でテストが失敗したとき、現場のスナップショットやネットワークログがないため、問題の再現と特定が非常に難しい。</li>
</ul>
<p>こうした問題を解決するために次世代のテストツールが登場し、Playwrightはその代表格となっている。</p>
<h2>2. Playwrightとは何か？</h2>
<p>PlaywrightはMicrosoftが開発したNode.jsライブラリで、Chromium（Chrome、Edge）、Firefox、WebKit（Safari）を自動操作する。Google Puppeteerを最初に開発したチームの中心メンバーが作ったもので、Puppeteerの精神的な後継者と見なせるが、設計はより現代的で強力である。</p>
<h2>3. Playwrightの主な強み</h2>
<h4>a. 真のクロスブラウザーテスト</h4>
<p>これはPlaywrightの最も際立った長所である。統一された一つのAPIを使い、主要な三つのブラウザーエンジンすべてで動くテストを書ける。Safariのような特定のブラウザーでしか発生しないバグも簡単に発見し、修正できる。</p>
<h4>b. 自動待機（Auto-Waits）</h4>
<p>Playwrightは非同期の問題を根本から解決する。<code>page.click()</code>などの操作を実行する前に、次のような一連の操作可能性チェックを自動で行う：</p>
<ul>
<li>要素がDOMに現れるまで待つ。</li>
<li>要素が表示されるまで待つ。</li>
<li>アニメーションが要素を覆わなくなるまで待つ。</li>
<li>要素がイベントを受け取れるまで待つ。</li>
</ul>
<p>そのため、手動の待機コードをほとんど書く必要がなくなり、テストの安定性が大幅に高まる。</p>
<h4>c. 強力な付属ツール</h4>
<ul>
<li>
<p><strong>Codegen（コードジェネレーター）</strong>：画期的な機能である。<code>pnpm exec playwright codegen example.com</code>を実行すると、Playwrightがブラウザーウィンドウを開く。そこで行ったすべての操作が自動的に記録され、テストコードへ変換される。E2Eテストを書くためのハードルを大きく下げてくれる。</p>
</li>
<li>
<p><strong>Trace Viewer（トレースビューアー）</strong>：Playwrightの「タイムマシン」である。テストに失敗したとき、完全なテストトレースファイルを生成できる。Trace Viewerで開けば、次のことが可能だ：</p>
<ul>
<li>テストの各ステップにおけるDOMスナップショットを確認する。</li>
<li>完全なネットワークリクエストログを確認する。</li>
<li>consoleログとエラー情報を確認する。</li>
<li>タイムラインを前後に動かし、各操作の前後でページがどう変化したかを直感的に確認する。</li>
</ul>
</li>
</ul>
<p>これにより、CIで失敗したケースのデバッグがかつてないほど簡単になる。</p>
<h2>4. 簡単なテスト例</h2>
<p>PlaywrightのAPIは非常に直感的に設計されている。</p>
<pre><code>import { test, expect } from '@playwright/test';

test('页面应有正确的标题', async ({ page }) =&gt; {
  await page.goto('https://playwright.dev/');

  // 断言页面的 title 包含 "Playwright"
  await expect(page).toHaveTitle(/Playwright/);
});

test('点击 "Get started" 链接应跳转到介绍页', async ({ page }) =&gt; {
  await page.goto('https://playwright.dev/');

  // 通过角色和名称定位并点击链接
  await page.getByRole('link', { name: 'Get started' }).click();

  // 断言 URL 包含 "intro"
  await expect(page).toHaveURL(/.*intro/);
});
</code></pre>
<h2>結論</h2>
<p>Playwrightは、優れたクロスブラウザー対応、信頼できる自動待機、比類のないデバッグツール（特にTrace Viewer）により、現代のWebアプリケーションにおけるE2Eテストの新たな基準を打ち立てた。テストの安定性と信頼性を高めるだけでなく、Codegenなどのツールによってテスト作成の体験も大きく改善する。プロジェクトに現代的で強力なテスト自動化手段を求めているなら、Playwrightは間違いなく有力な選択肢の一つだ。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[Signals：フロントエンド・リアクティビティの新潮流]]></title>
            <link>https://blog.m1ng.space/ja/posts/frameworks/the-rise-of-signals/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/frameworks/the-rise-of-signals/</guid>
            <pubDate>Sat, 20 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[SolidJS や Qwik から Preact、Svelte 5 まで、Signals は現代のフロントエンドフレームワークで高性能なリアクティブ更新を実現する中核的なパラダイムになりつつあります。本稿では、その仕組みとエコシステムへの影響を詳しく解説します。]]></description>
            <content:encoded><![CDATA[<h2>1. リアクティブモデルの進化</h2>
<p>フロントエンド開発の本質は「状態を UI に対応づけること」です。長年にわたり、リアクティブモデルは絶えず進化してきました。手動の DOM 操作から MVC/MVVM パターンへ、そして React が普及させた仮想 DOM（Virtual DOM）へと移り変わってきたのです。VDOM はコンポーネント単位で状態変更をまとめて処理し、Diffing を行うことで、UI 開発を大幅に簡素化しました。</p>
<p>しかし、VDOM は万能薬ではありません。コンポーネント単位の再レンダリングと Diffing のコストは、動的な処理が特に多い場面ではパフォーマンスのボトルネックになり得ます。近年、より古いパラダイムを現代のコンパイラで最適化した「きめ細かなリアクティビティ（Fine-Grained Reactivity）」が再び表舞台に戻り、その中核を担っているのが <strong>Signals</strong> です。</p>
<h2>2. Signals とは？</h2>
<p>Signal は、値を包み込み、その値が変化したときにすべての依存先へ自動的に通知できるリアクティブプリミティブ（Reactive Primitive）です。コンポーネント単位で変化を追跡する VDOM フレームワークとは異なり、Signal はデータが読み取られる段階で依存関係グラフを自動的に構築します。</p>
<p>Signal の値が更新されると、その Signal に直接または間接的に依存する計算（<code>Memo</code>）や副作用（<code>Effect</code>）だけが再実行されます。これにより「外科手術」のように正確な DOM 更新が可能になり、VDOM の Diffing はまったく必要ありません。</p>
<p>その中核は通常、次の 3 つのプリミティブで構成されます。</p>
<ul>
<li><strong><code>createSignal(value)</code></strong>: リアクティブな state の単位を作成します。</li>
<li><strong><code>createEffect(() =&gt; {})</code></strong>: 依存関係を自動追跡し、変更に反応する副作用を作成します。</li>
<li><strong><code>createMemo(() =&gt; {})</code></strong>: 派生した、キャッシュ付きのリアクティブな計算を作成します。</li>
</ul>
<pre><code>// SolidJS 语法示例
const [count, setCount] = createSignal(0);

const doubleCount = createMemo(() =&gt; count() * 2);

createEffect(() =&gt; {
  console.log(`The double count is: ${doubleCount()}`);
});

setCount(1); // 这将触发 memo 重新计算，并触发 effect 重新执行
</code></pre>
<p>重要なメンタルモデルは、SolidJS のような Signal ベースのフレームワークでは、コンポーネント関数そのものは初期化時に一度だけ実行されるという点です。その後の更新はコンポーネントの再レンダリングではなく、リアクティブシステムによって完全に駆動されます。</p>
<h2>3. エコシステム全体での幅広い採用</h2>
<p>Signal はまったく新しい概念ではなく、その考え方は Knockout.js など初期のフレームワークにまで遡れます。しかし、現代の JavaScript コンパイラによって新たな活力を得て、主要なフレームワークに幅広く採用されています。</p>
<ul>
<li><strong>SolidJS &amp; Qwik</strong>: Signal を全面的な基盤として構築されており、このパラダイムの模範的な実装です。</li>
<li><strong>Preact</strong>: <code>@preact/signals</code> パッケージによって公式サポートを導入し、既存の Preact/React プロジェクトにも統合できます。</li>
<li><strong>Vue</strong>: Composition API の <code>ref</code> と <code>computed</code> は、本質的には Signal の一種の実装です。</li>
<li><strong>Svelte 5</strong>: まもなく登場する「Runes」アップデートは、Svelte チームによるリアクティブモデルの再構築であり、その中核では Signal パラダイムを参考にして実装しています。</li>
<li><strong>Angular</strong>: 最近のバージョンでは、新しいリアクティブプリミティブとして Signals が導入されています。</li>
</ul>
<p>このようにフレームワークをまたいで同じ方向へ収束していることは、効率的で予測可能なリアクティブモデルとしての Signal の価値を証明しています。</p>
<h2>4. 利点とトレードオフ</h2>
<p><strong>利点：</strong></p>
<ol>
<li><strong>優れたパフォーマンス</strong>: VDOM とコンポーネント単位の再レンダリングを回避するため、ベンチマークでは通常、優秀な結果を示します。</li>
<li><strong>予測可能性</strong>: 状態更新の流れが明確で、理解やデバッグが容易です。</li>
<li><strong>少ないメモリ使用量</strong>: コンポーネントツリー全体の仮想表現を保持する必要がありません。</li>
</ol>
<p><strong>トレードオフ：</strong></p>
<ol>
<li><strong>メンタルモデルの転換</strong>: React のレンダリングサイクルに慣れた開発者は、「コンポーネントは一度しか実行されない」という新しいモデルに適応する必要があります。</li>
<li><strong>エコシステムとの統合</strong>: Signals 自体は高性能ですが、巨大な React VDOM エコシステム（たとえば一部の UI ライブラリ）と深く統合するには、追加の適応作業が必要になる場合があります。</li>
</ol>
<h2>まとめ</h2>
<p>Signals の復興は、フロントエンドにおける状態管理パラダイムの重要な進化を示しています。開発者の意識を「コンポーネントがどのようにレンダリングされるか」から、より本質的な「状態がどのように流れるか」という問題へと引き戻しました。コンパイラとの深い統合により、Signal は優れた開発体験を提供しながら、Web アプリケーションのパフォーマンス限界に新たな可能性をもたらします。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[APIドキュメントに別れを：tRPCでエンドツーエンドの型安全なアプリケーションを構築する]]></title>
            <link>https://blog.m1ng.space/ja/posts/typescript/typesafe-apis-with-trpc/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/typescript/typesafe-apis-with-trpc/</guid>
            <pubDate>Wed, 15 Mar 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[フルスタックTypeScriptプロジェクトで、フロントエンドとバックエンドのデータ契約をどう同期させるか。tRPCはコード生成も中間スキーマも使わず、真のエンドツーエンド型安全性を実現する。]]></description>
            <content:encoded><![CDATA[<h2>1. フロントエンドとバックエンドをつなぐ「契約」の難しさ</h2>
<p>従来のフロントエンドとバックエンドを分離した開発では、APIが両者の「契約」となる。通常は次の方法でこの契約を管理する：</p>
<ul>
<li><strong>RESTful API</strong>：OpenAPI（Swagger）などのツールを使い、詳しいAPIドキュメントを生成、管理する。</li>
<li><strong>GraphQL</strong>：厳密なSchema Definition Language（SDL）を使い、データ構造と操作を定義する。</li>
</ul>
<p>これらの方法は有効だが、共通の問題がある。<strong>契約と実装が分離している</strong>ことだ。フロントエンド開発者がAPIを呼び出すとき、そのAPIがドキュメントやスキーマに書かれたデータ構造を返すと信じる。しかしバックエンドの実装が変わり、たとえばフィールド名が変更されたのに、ドキュメントやスキーマが間に合って更新されなければ、その不一致は実行時になって初めて表面化し、バグを引き起こす。</p>
<p>この「契約」を実装と自動的に同期させ、さらにはコンパイル時に不一致を発見する方法はないだろうか？</p>
<h2>2. tRPCの中心思想：スキーマではなく型を共有する</h2>
<p>tRPC（TypeScript Remote Procedure Call）は、抜本的だが非常に単純な方法を提案する。<strong>フロントエンドとバックエンドの両方でTypeScriptを使うなら、型をそのまま共有すればよいのではないか？</strong></p>
<p>tRPCでは、純粋なTypeScript関数をバックエンドAPIとして記述し、フロントエンドから直接呼び出せる。ローカルモジュールの関数を呼ぶように、完全な型推論と自動補完を利用できる。</p>
<p>スキーマにもコード生成にも依存しない。唯一の「契約」はTypeScriptの型そのものである。</p>
<h2>3. どのように動くのか？</h2>
<p>tRPCの魔法は、型推論と少し巧妙なカプセル化にある。</p>
<h4>a. バックエンド：API Routerを定義する</h4>
<p>バックエンド（通常はNode.jsサービス）では、tRPCの関数を使って一つ以上の「Router」を作成する。各Routerは、呼び出し可能な「Procedure」、つまりAPIエンドポイントの集合である。</p>
<pre><code>// server/router.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod'; // 使用 Zod 进行运行时校验

const t = initTRPC.create();

export const appRouter = t.router({
  // 定义一个名为 `getUser` 的查询 procedure
  getUser: t.procedure
    .input(z.object({ userId: z.string() }))
    .query(({ input }) =&gt; {
      // 在这里查询数据库或执行其他逻辑
      const user = { id: input.userId, name: 'Alex' };
      return user;
    }),

  // 定义一个名为 `createUser` 的变更 procedure
  createUser: t.procedure
    .input(z.object({ name: z.string() }))
    .mutation(({ input }) =&gt; {
      const user = { id: `${Math.random()}`, name: input.name };
      return user;
    }),
});

// 导出 router 的类型定义
export type AppRouter = typeof appRouter;
</code></pre>
<h4>b. フロントエンド：クライアントを作成してAPIを呼び出す</h4>
<p>フロントエンドでは、バックエンドから<code>AppRouter</code>という<strong>型</strong>だけをインポートすればよい。サーバー側のコードではなく、型だけをインポートしている点が重要だ。</p>
<pre><code>// client/trpc.ts
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '../server/router'; // 只导入类型

export const trpc = createTRPCReact&lt;AppRouter&gt;();
</code></pre>
<p>これでReactコンポーネントから、ローカル関数のようにAPIを呼び出し、完全な型安全性と自動補完を利用できる。</p>
<pre><code>// client/components/UserInfo.tsx
import { trpc } from '../trpc';

function UserInfo({ userId }: { userId: string }) {
  // `useQuery` 的第一个参数是 procedure 的路径
  // 你输入 `trpc.` 时，IDE 会自动提示 `getUser` 和 `createUser`
  const userQuery = trpc.getUser.useQuery({ userId });

  if (userQuery.isLoading) {
    return &lt;div&gt;Loading...&lt;/div&gt;;
  }

  // `userQuery.data` 的类型被自动推断为 { id: string; name: string }
  return &lt;div&gt;User: {userQuery.data?.name}&lt;/div&gt;;
}
</code></pre>
<p>この時点でバックエンド開発者が、<code>getUser</code>の返す<code>name</code>フィールドを<code>fullName</code>に変更すると、フロントエンドの<code>userQuery.data?.name</code>は実行時を待たず、TypeScriptのコンパイル時にすぐエラーになる。</p>
<h2>4. tRPCを選ぶ理由</h2>
<ul>
<li><strong>完全なエンドツーエンド型安全性</strong>：これが中心的な価値である。API契約の不一致によって発生する一群のバグを取り除ける。</li>
<li><strong>優れた開発者体験</strong>：IDEの自動補完により、ドキュメントを調べたりAPI構造を推測したりする必要がない。リファクタリングも非常に簡単かつ安全になる。</li>
<li><strong>コード生成が不要</strong>：追加のビルド工程がなく、フィードバックループが極めて速い。</li>
<li><strong>軽量で柔軟</strong>：tRPC自体は非常に小さく、どのフロントエンドフレームワークやバックエンドサービスとも連携できる。</li>
</ul>
<h2>結論</h2>
<p>tRPCは、フルスタックTypeScript開発にこれまでにない滑らかな体験をもたらす。APIドキュメントとスキーマへの依存をなくすことで、フロントエンドとバックエンドの連携をシームレスかつ非常に安全にする。モノレポ構成では、その長所がさらに際立つ。フルスタックTypeScriptアプリケーションを構築しているなら、tRPCは時間をかけて試す価値のある画期的なツールだ。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[Astroを探る：コンテンツ駆動型サイトのために生まれたフレームワーク]]></title>
            <link>https://blog.m1ng.space/ja/posts/astro/exploring-astro-for-content-sites/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/astro/exploring-astro-for-content-sites/</guid>
            <pubDate>Tue, 10 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[シングルページアプリケーション（SPA）が全盛の今、Astroは別の道を選び、コンテンツサイトの究極のパフォーマンスに注力しています。その「アイランドアーキテクチャ」にはどのような力があるのでしょうか。]]></description>
            <content:encoded><![CDATA[<h2>1. 本当にそれほど多くのJavaScriptが必要なのか？</h2>
<p>React、Vue、Svelteなどのモダンなフロントエンドフレームワークは、複雑なWebアプリケーションを構築する開発体験を大きく向上させました。しかし、それらをブログ、ポートフォリオ、ドキュメント、マーケティングサイトの構築に使うと、ある疑問が生じます。主にコンテンツを表示するこれらのサイトで、本当にページ全体をシングルページアプリケーション（SPA）として読み込む必要があるのでしょうか。</p>
<p>答えはたいてい「いいえ」です。この種のサイトでユーザーが最も必要としているのは、コンテンツへ素早くアクセスすることです。JavaScriptが多すぎると、かえって操作可能になるまでの時間（TTI）が遅くなり、ユーザー体験とSEOに悪影響を与えます。</p>
<p>Astroは、まさにこの問題を解決するために生まれました。</p>
<h2>2. Astroの中核理念：コンテンツ優先、デフォルトでゼロJS</h2>
<p>Astroはモダンな静的サイトジェネレーター（SSG）であり、その中核理念は<strong>コンテンツ優先</strong>です。できるだけ多くの作業をビルド時に完了し、ブラウザーへ送るJavaScriptを可能な限り少なくすることを目指しています。</p>
<p>そのために、Astroは2つの大きな革新を打ち出しました。</p>
<ul>
<li><strong>デフォルトでゼロJavaScript（Zero-JS by Default）</strong>：Astroは、React、Vue、Svelteのいずれで書かれていても、すべてのUIコンポーネントをビルド時に純粋なHTMLへレンダリングします。そのためブラウザーが受け取るのは静的ページであり、フレームワークのJSランタイムを読み込む必要がなく、非常に高速に表示できます。</li>
<li><strong>アイランドアーキテクチャ（Islands Architecture）</strong>：これこそがAstroの真髄です。静的HTMLでできた「海」の中で、クライアント側の操作が必要なコンポーネントだけを「島」として指定できます。Astroはそれらの島に必要なJavaScriptを個別にバンドルして読み込み、ページの残りは完全に静的なまま保ちます。</li>
</ul>
<h2>3. 「島」はどのように動くのか？</h2>
<p>Astroでは、<code>client:*</code>ディレクティブを追加することで、コンポーネントを対話可能な島として指定できます。</p>
<p>たとえば、Reactで書かれた<code>Counter.jsx</code>というカウンターコンポーネントがあるとします。Astroページでは次のように使用できます。</p>
<pre><code>---
// src/pages/index.astro
import Counter from '../components/Counter.jsx';
---
&lt;html&gt;
  &lt;body&gt;
    &lt;h1&gt;Astro 示例&lt;/h1&gt;
    &lt;p&gt;这是一个静态的段落，它不会加载任何 JS。&lt;/p&gt;

    {/* 这个组件是一个交互式岛屿 */}
    &lt;Counter client:load /&gt;

    &lt;p&gt;这是另一个静态段落。&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p><code>client:load</code>ディレクティブはAstroに次のことを指示します。</p>
<ol>
<li>サーバー側で<code>Counter</code>コンポーネントの初期HTMLをレンダリングする。</li>
<li><code>Counter</code>コンポーネント用に独立したJSバンドルを作成する。</li>
<li>ページ読み込み時にこのJSバンドルを自動で読み込み、コンポーネントを「有効化」（hydrate）して操作可能にする。</li>
</ol>
<p>Astroには、<code>client:idle</code>（ブラウザーがアイドル状態のときに読み込む）や<code>client:visible</code>（コンポーネントがビューポートに入ったときに読み込む）など、さらに細かな読み込みディレクティブもあり、パフォーマンス最適化を一段と進められます。</p>
<h2>4. フレームワーク非依存</h2>
<p>Astroのもう一つの大きな魅力は、UIフレームワークに対する柔軟性です。同じAstroプロジェクト内で、React、Vue、Svelte、SolidJS、Litなど異なるフレームワークのコンポーネントを同時に利用できます。これにより、チームでの協働や技術選定に大きな柔軟性が生まれます。</p>
<h2>結論</h2>
<p>AstroはReactやVueを置き換えるものではなく、特定の場面により適した解決策を提供するものです。プロジェクトがコンテンツ中心で、パフォーマンスとSEOに非常に高い要件を持つサイトであるなら（たとえば、このブログ自体もAstroで構築されています）、Astroは間違いなく深く探る価値のある優れた選択肢です。静的サイトのパフォーマンス上の利点と、モダンなフレームワークの開発体験を見事に組み合わせています。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[SvelteKit 1.0 正式リリース：次世代の Web アプリケーション構築手法]]></title>
            <link>https://blog.m1ng.space/ja/posts/svelte/sveltekit-1-0-release/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/svelte/sveltekit-1-0-release/</guid>
            <pubDate>Thu, 01 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[2 年以上にわたる開発を経て、SvelteKit 1.0 が 2022 年 12 月についに正式リリースされました。あらゆる規模の Web アプリケーション構築の未来と評される、その中核機能と設計思想を紹介します。]]></description>
            <content:encoded><![CDATA[<h2>SvelteKit 1.0 が登場！</h2>
<p>2022 年 12 月、Svelte チームは SvelteKit 1.0 のリリースを正式に発表しました。これは Svelte コミュニティだけでなく、フロントエンド分野全体にとっても画期的な出来事です。SvelteKit は、もはや単なる「Svelte 版の Next.js や Nuxt.js」ではありません。独自の設計思想を携え、よりシンプルで柔軟、かつ高性能な Web アプリケーション構築手法を提供することを目指しています。</p>
<h2>SvelteKit とは？</h2>
<p>Svelte に詳しい方なら、Svelte 自体が<strong>コンポーネントフレームワーク</strong>であることをご存じでしょう。大胆なコンパイラによって、ビルド時に <code>.svelte</code> ファイルを効率的な命令型 JavaScript コードへ変換し、驚異的なパフォーマンスと極めて小さなランタイムオーバーヘッドを実現します。</p>
<p>一方、SvelteKit は Svelte 上に構築された<strong>アプリケーションフレームワーク</strong>です。ルーティング、サーバーサイドレンダリング（SSR）、データ読み込み、デプロイアダプターなど、完全なアプリケーションの構築に必要なすべてを処理するため、開発者はビジネスロジックの開発に集中できます。</p>
<h2>中核機能の概要</h2>
<h4>1. ファイルシステムベースのルーティング</h4>
<p>Next.js と同じように、SvelteKit のルートはファイルシステムの構造から自動的に生成されます。<code>src/routes</code> ディレクトリ以下のファイル構造が、アプリケーションの URL に直接対応します。</p>
<ul>
<li><code>src/routes/+page.svelte</code> -&gt; <code>/</code></li>
<li><code>src/routes/about/+page.svelte</code> -&gt; <code>/about</code></li>
<li><code>src/routes/blog/[slug]/+page.svelte</code> -&gt; <code>/blog/some-post</code></li>
</ul>
<p>設定より規約を優先するこの方法により、ルート管理が大幅に簡素化されます。</p>
<h4>2. 柔軟なレンダリングモード</h4>
<p>SvelteKit では、ページ単位でレンダリング方法を細かく制御できます。サーバーサイドレンダリング（SSR）、静的サイト生成（SSG）、またはその両方を組み合わせた構成を、同じアプリケーション内で実現できます。単一のページだけ SSR を無効にし、純粋なクライアントサイドのシングルページアプリケーション（SPA）にすることさえ可能です。</p>
<h4>3. 汎用的な <code>load</code> 関数</h4>
<p>SvelteKit はデータ読み込みのパターンを統一します。各ページ（またはレイアウト）と同じディレクトリに <code>+page.js</code> または <code>+page.server.js</code> ファイルを作成し、<code>load</code> 関数をエクスポートできます。</p>
<ul>
<li><code>+page.js</code> の <code>load</code> 関数は、サーバーとクライアントの両方で実行されます。</li>
<li><code>+page.server.js</code> の <code>load</code> 関数は<strong>サーバー上でのみ</strong>実行されるため、データベースや非公開 API へ安全にアクセスできます。</li>
</ul>
<p><code>load</code> 関数が返したデータは、対応する <code>+page.svelte</code> コンポーネントへ自動的に渡されます。</p>
<pre><code>// src/routes/blog/[slug]/+page.server.js
import * as db from '$lib/server/database';

export async function load({ params }) {
  const post = await db.getPost(params.slug);
  return { post };
}
</code></pre>
<h4>4. アダプター</h4>
<p>「一度書けば、どこへでもデプロイできる」ことは、SvelteKit の中心的な約束の一つです。<strong>アダプター</strong>を利用すると、対象とするあらゆるプラットフォームに適した形式でアプリケーションをパッケージ化できます。</p>
<ul>
<li><code>@sveltejs/adapter-node</code>: 従来の Node.js サーバーへのデプロイに使用します。</li>
<li><code>@sveltejs/adapter-vercel</code>: Vercel プラットフォームに対応します。</li>
<li><code>@sveltejs/adapter-static</code>: アプリケーション全体を静的ファイルとしてプリレンダリングし、あらゆる静的ホスティングで利用できるようにします。</li>
<li>Netlify や Cloudflare Workers などのプラットフォームに対応する、さらに多くの公式・コミュニティ製アダプターがあります。</li>
</ul>
<h2>まとめ</h2>
<p>SvelteKit 1.0 のリリースは、Svelte エコシステムの成熟を示しました。Svelte コンパイラの究極的なパフォーマンスと、入念に設計されたアプリケーションフレームワークを組み合わせ、強力で快適な開発体験を提供します。シンプルな静的ページから複雑な動的アプリケーションまで構築できる万能なフレームワークを探しているなら、SvelteKit は間違いなく試す価値があります。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[React 状態管理の変遷：Props Drilling から Zustand まで]]></title>
            <link>https://blog.m1ng.space/ja/posts/react/state-management-evolution/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/react/state-management-evolution/</guid>
            <pubDate>Tue, 15 Nov 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[React の状態管理は、初期の「Props Drilling」から Redux による統一的な手法を経て、現在の Zustand など軽量ライブラリが花開く時代へと進化してきました。本稿では、その興味深い歴史を振り返ります。]]></description>
            <content:encoded><![CDATA[<h2>はじめに</h2>
<p>「状態をどのように美しく管理するか？」これは、プロジェクトが成長する過程ですべての React 開発者が向き合わなければならない中心的な問題です。単純なコンポーネント内部の状態から、複数のコンポーネントにまたがる複雑なグローバル状態まで、React コミュニティはさまざまな解決策を探ってきました。これらの手法の進化は、コンポーネント指向の開発に対する理解が深まってきたことも表しています。</p>
<h2>第 1 段階：素朴な時代 — <code>useState</code> と Props Drilling</h2>
<p>当初、利用できるのは <code>useState</code>（またはクラスコンポーネントの <code>this.state</code>）だけでした。ある状態を複数のコンポーネントで共有する必要がある場合、React の公式な推奨は <strong>「状態のリフトアップ（Lifting State Up）」</strong> でした。状態をそれらのコンポーネントに最も近い共通の親へ移し、そこから props を通じて状態と更新関数を渡します。</p>
<p>コンポーネントの階層が深くなると、このパターンは <strong>「Props Drilling」</strong> を引き起こします。中間層のコンポーネントが、自身ではまったく利用しない props を、より深い子コンポーネントへ渡すためだけに受け取る状態です。これによってコンポーネント間の結合が強くなり、リファクタリングや保守が難しくなりました。</p>
<h2>第 2 段階：公式の回答 — Context API</h2>
<p>Props Drilling を解決するため、React は公式に Context API を提供しました。「コンテキスト」を作成し、コンポーネントツリーの上層で値を提供（Provide）すれば、どれほど深い位置の子コンポーネントでも値を直接利用（Consume）でき、階層ごとに手動で渡す必要がなくなります。</p>
<pre><code>// 1. 创建 Context
const ThemeContext = React.createContext('light');

// 2. 在顶层提供值
&lt;ThemeContext.Provider value="dark"&gt;
  &lt;App /&gt;
&lt;/ThemeContext.Provider&gt;

// 3. 在子组件中消费
const theme = useContext(ThemeContext); // 'dark'
</code></pre>
<p>しかし、Context API にも「落とし穴」があります。それは<strong>パフォーマンスの問題</strong>です。<code>Provider</code> の <code>value</code> が変化すると、その Context を利用している<strong>すべての</strong>コンポーネントが再レンダリングされます。たとえ必要なのが <code>value</code> オブジェクトのごく一部だけでも同じです。そのため Context API は、頻繁に変化する複雑なグローバル状態の管理には適していません。</p>
<h2>第 3 段階：統一の時代 — Redux</h2>
<p>Context API がまだ成熟していなかった時代に Redux が登場し、大規模で複雑なアプリケーションにおける状態管理の事実上の標準へと急速に成長しました。Flux アーキテクチャと関数型プログラミングの考え方を取り入れ、次の原則をもたらしました。</p>
<ul>
<li><strong>信頼できる唯一の情報源（Single Source of Truth）</strong>: アプリケーション全体の state を単一の store に保存します。</li>
<li><strong>State は読み取り専用</strong>: state を変更する唯一の方法は action を dispatch することです。</li>
<li><strong>変更には純粋関数を使う</strong>: Reducer は以前の state と action を受け取り、新しい state を返します。</li>
</ul>
<p>Redux は予測可能性、強力なデバッグツール（タイムトラベル）、豊富なミドルウェアのエコシステムによって、大規模アプリケーションの状態管理問題を解決しました。しかし、欠点も同じくらい明らかでした。煩雑な <strong>ボイラープレート（Boilerplate）</strong> です。単純な機能を実現するだけでも Actions、Reducers、Dispatchers を記述する必要があり、開発者の認知的な負担は大きくなりました。</p>
<h2>第 4 段階：ルネサンス — 軽量で Hooks-First な手法</h2>
<p>React Hooks の普及と Redux の複雑さに対する見直しを背景に、コミュニティでは新しく、より軽量な状態管理ライブラリが次々と登場しました。簡潔な API、単純なメンタルモデル、Hooks の能力を十分に活かすことが共通の特徴です。</p>
<p><strong>Zustand</strong> はその優れた代表例です。非常に簡単な <code>create</code> 関数で store を作成でき、次の特徴があります。</p>
<ul>
<li><strong>Provider が不要</strong>: Store は React コンポーネントツリーの外部に存在し、どこからでもインポートして利用できます。</li>
<li><strong>最小限の API</strong>: 1 つの Hook だけで状態へのアクセスと更新ができます。</li>
<li><strong>選択的な購読による高いパフォーマンス</strong>: コンポーネントは必要な state の部分だけを購読でき、Context API のパフォーマンス問題を回避します。</li>
</ul>
<pre><code>const useStore = create(set =&gt; ({
  count: 0,
  inc: () =&gt; set(state =&gt; ({ count: state.count + 1 })),
}));

function Counter() {
  // 只订阅 count 的变化
  const count = useStore(state =&gt; state.count);
  return &lt;h1&gt;{count}&lt;/h1&gt;;
}
</code></pre>
<h2>まとめ：銀の弾丸はない、必要に応じて選ぶ</h2>
<p>React 状態管理の変遷は、永続的な「最良の手法」はなく、「現在の状況に最も適した手法」だけがあることを教えてくれます。</p>
<ul>
<li><strong><code>useState</code></strong>: コンポーネントのローカル状態では常に第一の選択肢です。</li>
<li><strong>Context API</strong>: テーマやユーザー認証情報など、頻繁には変化しないグローバルデータの管理に適しています。</li>
<li><strong>Zustand / Jotai</strong>: クライアント側のグローバル状態が必要なほとんどのアプリケーションにとって、パフォーマンスと開発体験の絶妙なバランスを提供します。</li>
<li><strong>Redux（Redux Toolkit）</strong>: 厳格なデータフロー規約、複雑なミドルウェア、強力なデバッグ能力が必要な超大規模アプリケーションでは、今も信頼できる選択肢です。</li>
</ul>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[WebpackからViteへ：スムーズな移行の旅]]></title>
            <link>https://blog.m1ng.space/ja/posts/build-tools/migrating-from-webpack-to-vite/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/build-tools/migrating-from-webpack-to-vite/</guid>
            <pubDate>Mon, 05 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Webpackプロジェクトの起動に1分、ホット更新に十数秒かかっていませんか。次世代のフロントエンドビルドツールを採用するときです。この記事では、WebpackからViteへ移行した手順と学びを記録します。]]></description>
            <content:encoded><![CDATA[<h2>1. なぜ移行するのか？Webpackの悩み</h2>
<p>Webpackは非常に強力で設定の自由度が高いモジュールバンドラーであり、長年にわたってフロントエンドプロジェクトの基盤でした。しかし、プロジェクトの規模が大きくなるにつれ、「バンドル」を中心とする考え方が性能上のボトルネックを生みます。</p>
<ul>
<li><strong>遅いコールドスタート</strong>：開発サーバー（<code>dev-server</code>）を起動するたびに、Webpackは依存関係グラフ全体をたどり、すべてのモジュールをメモリ内にバンドルする必要があります。大規模なプロジェクトでは、この処理に数分かかることがあります。</li>
<li><strong>遅いホット更新（HMR）</strong>：ファイルを変更すると、Webpackは関連するモジュールを再計算して置き換える必要があります。ページ全体の再読み込みよりは速いものの、大規模プロジェクトでは数秒から十数秒遅れることもあり、開発の流れを中断します。</li>
</ul>
<h2>2. Viteはどのように問題を解決するのか？</h2>
<p>フランス語で「速い」を意味するViteは、別の道を選びました。モダンブラウザーがネイティブESモジュール（ESM）をサポートしていることを活用し、ビルド工程を2つに分けます。</p>
<ul>
<li><strong>開発時</strong>：Viteはサーバーを起動しますが、すべてのモジュールを事前にバンドルしません。代わりにブラウザーからのモジュール要求を受け取り、必要に応じてソースコードを変換して提供します。たとえばブラウザーが<code>main.js</code>を要求するとViteがそれを提供し、<code>main.js</code>が<code>Button.vue</code>をimportするとブラウザーが再び要求を送り、Viteが変換済みの<code>Button.vue</code>を提供します。そのため開発サーバーはほぼ瞬時に起動します。</li>
<li><strong>本番時</strong>：Viteは同じく効率的なバンドラーであるRollupを使い、高度に最適化された静的アセットを生成します。</li>
</ul>
<p>この方式は開発体験を一変させ、電光石火の起動とミリ秒単位のホット更新を実現します。</p>
<h2>3. 実践的な移行手順</h2>
<p>既存のWebpackプロジェクトをViteへ移行する場合、通常は次の手順を行います。</p>
<h4>a. 依存関係をインストールし、設定ファイルを作成する</h4>
<p>まずViteをインストールします。</p>
<pre><code>pnpm add -D vite @vitejs/plugin-react # 或 @vitejs/plugin-vue
</code></pre>
<p>次にプロジェクトのルートに<code>vite.config.js</code>を作成します。</p>
<pre><code>import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [react()],
})
</code></pre>
<h4>b. <code>index.html</code>を移動する</h4>
<p>Webpackでは通常、<code>index.html</code>を<code>public</code>ディレクトリに置き、バンドル済みのJSを自動挿入します。Viteは<code>index.html</code>をアプリケーションのエントリーポイントとして扱います。これをプロジェクトのルートへ移し、スクリプト参照を手動で追加する必要があります。</p>
<pre><code>
&lt;body&gt;
  &lt;div id="root"&gt;&lt;/div&gt;
  &lt;script type="module" src="/src/main.jsx"&gt;&lt;/script&gt;
&lt;/body&gt;
</code></pre>
<h4>c. Webpackプラグインを置き換える</h4>
<p>WebpackのLoadersとPluginsに対応するViteプラグインを探す必要があります。コミュニティのエコシステムは豊富で、ほとんどの要件に解決策が見つかります。</p>
<table>
<thead>
<tr>
<th>Webpack</th>
<th>Vite</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>babel-loader</code></td>
<td><code>@vitejs/plugin-react</code>（Babel内蔵）</td>
</tr>
<tr>
<td><code>vue-loader</code></td>
<td><code>@vitejs/plugin-vue</code></td>
</tr>
<tr>
<td><code>file-loader</code></td>
<td>Viteに内蔵</td>
</tr>
<tr>
<td><code>webpack-dev-server</code></td>
<td>Viteに開発サーバーを内蔵</td>
</tr>
</tbody>
</table>
<h4>d. 環境変数を扱う</h4>
<p>Webpackでは<code>process.env.NODE_ENV</code>を使うことに慣れています。Viteでは<code>import.meta.env</code>を通して環境変数へアクセスする必要があります。たとえば<code>import.meta.env.VITE_API_URL</code>です。</p>
<h4>e. パスエイリアスを設定する</h4>
<p><code>vite.config.js</code>でのパスエイリアス設定は非常に簡単です。</p>
<pre><code>import path from 'node:path'
// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  // ...
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})
</code></pre>
<h2>4. 移行後の成果</h2>
<p>Viteへ移行した後、最も直感的に感じるのは<strong>速さ</strong>です。</p>
<ul>
<li>開発サーバーの起動時間は<strong>50秒</strong>から<strong>2秒</strong>に短縮されました。</li>
<li>ホット更新は<strong>平均3〜5秒</strong>から、<strong>ほとんど感じない数十ミリ秒</strong>に短縮されました。</li>
<li>設定ファイル（<code>vite.config.js</code>）は<code>webpack.config.js</code>より大幅に簡素になりました。</li>
</ul>
<h2>結論</h2>
<p>移行中にプロジェクト固有の設定問題へ対処する必要があるかもしれませんが、WebpackからViteへ移ることで開発体験は大きく向上します。まだ遅いビルド処理に耐えているなら、今こそViteを採用する絶好のタイミングです。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[ゼロランタイム CSS-in-JS：開発体験と最高のパフォーマンスを両立する]]></title>
            <link>https://blog.m1ng.space/ja/posts/css/zero-runtime-css-in-js/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/css/zero-runtime-css-in-js/</guid>
            <pubDate>Fri, 05 Aug 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[CSS-in-JS は優れた開発体験を提供しますが、実行時のパフォーマンスコストは常に議論の対象でした。ゼロランタイム CSS-in-JS はビルド時にスタイルを静的 CSS ファイルへ抽出し、両方の利点を実現します。]]></description>
            <content:encoded><![CDATA[<h2>1. CSS-in-JS という「諸刃の剣」</h2>
<p><code>styled-components</code> や <code>Emotion</code> などの CSS-in-JS は、JavaScript／TypeScript ファイル内に CSS を記述できるようにし、コンポーネント開発におけるスタイル管理を一変させました。多くの利点があります。</p>
<ul>
<li><strong>コンポーネントスコープ</strong>: デフォルトでスタイルがコンポーネントに結び付くため、CSS のグローバルな名前衝突を解決します。</li>
<li><strong>動的スタイル</strong>: コンポーネントの props や state に基づく動的なスタイルを簡単に作成できます。</li>
<li><strong>コードの同居</strong>: スタイルとコンポーネントロジックを同じファイルに置けるため、保守と整理が容易になります。</li>
</ul>
<p>しかし、これらの利便性にコストがないわけではありません。従来の CSS-in-JS ライブラリの中心には <strong>ランタイム（Runtime）</strong> があります。コンポーネントがブラウザにマウントされると、CSS-in-JS ライブラリの JavaScript ランタイムは次の処理を行います。</p>
<ol>
<li>テンプレート文字列またはオブジェクト内の CSS を解析します。</li>
<li>一意のクラス名を生成します。</li>
<li>ドキュメントの <code>&lt;head&gt;</code> 内にある <code>&lt;style&gt;</code> タグへスタイルを動的に挿入します。</li>
</ol>
<p>この処理は JavaScript バンドルのサイズを増やし、アプリケーションの起動とレンダリング時に計算コストを加えるため、パフォーマンスに影響します。</p>
<h2>2. 「ゼロランタイム」による打開策</h2>
<p>実行時パフォーマンスの問題を解決するため、コミュニティは <strong>ゼロランタイム（Zero-Runtime）CSS-in-JS</strong> という新しい考え方を提案しました。</p>
<p>核となる考え方は、CSS-in-JS の開発体験を残しながら、すべての処理を <strong>ビルド時（build time）</strong> に完了させることです。通常は Babel プラグインや Vite プラグインであるビルドツールがコードを走査し、CSS-in-JS の使用箇所をすべて見つけて、次の処理を行います。</p>
<ol>
<li>CSS テキストを抽出します。</li>
<li>静的な <code>.css</code> ファイルを生成します。</li>
<li>元の CSS-in-JS コードを、生成された一意のクラス名に置き換えます。</li>
</ol>
<p>最終的にブラウザへ渡される JavaScript バンドルには <strong>CSS-in-JS のランタイムライブラリが一切含まれず</strong>、高度に最適化された静的 CSS ファイルを手書きした場合と同じ結果になります。</p>
<h2>3. 主なゼロランタイムソリューション</h2>
<h4>a. Linaria</h4>
<p>Linaria はゼロランタイム分野の先駆者の一つです。使い慣れた <code>styled</code> タグ付きテンプレートリテラル構文を使用できます。</p>
<pre><code>// YourComponent.js
import { styled } from '@linaria/react';

const Title = styled.h1`
  font-size: 2rem;
  color: tomato;
`;

// 构建时，这会被转换为：
// &lt;h1 class="Title_a1b2c3d"&gt;...&lt;/h1&gt;
//
// 并在一个静态 .css 文件中生成：
// .Title_a1b2c3d {
//   font-size: 2rem;
//   color: tomato;
// }
</code></pre>
<h4>b. vanilla-extract</h4>
<p>SEEK 社のチームが開発した vanilla-extract はさらに一歩進み、TypeScript を利用して完全に型安全なスタイルを作成します。すべてのスタイル定義は <code>.css.ts</code> ファイルからエクスポートされる変数であり、強力な型推論と自動補完を提供します。</p>
<pre><code>// styles.css.ts
import { style } from '@vanilla-extract/css';

export const title = style({
  fontSize: '2rem',
  color: 'tomato',
});
</code></pre>
<h4>c. Panda CSS</h4>
<p>Panda CSS は比較的新しい競合です。Tailwind CSS の考え方を取り入れ、「Style Props」による開発体験を提供しながら、ゼロランタイムの出力を保証します。</p>
<pre><code>import { css } from '../styled-system/css';

function MyComponent() {
  return &lt;div className={css({ fontSize: '2rem', color: 'tomato' })} /&gt;;
}
</code></pre>
<h2>4. 利点とトレードオフ</h2>
<p><strong>利点</strong>:</p>
<ul>
<li><strong>最高のパフォーマンス</strong>: 最終成果物は静的 CSS であり、JavaScript ランタイムのコストがありません。</li>
<li><strong>小さなバンドルサイズ</strong>: クライアントで CSS-in-JS ライブラリを読み込む必要がありません。</li>
<li><strong>優れた開発体験</strong>: コンポーネントスコープ、TypeScript の型安全性、コードの同居という利点を引き続き得られます。</li>
</ul>
<p><strong>トレードオフ</strong>:</p>
<ul>
<li><strong>ビルド時の依存</strong>: ビルド工程へ統合する必要があり、設定はやや複雑になります。</li>
<li><strong>動的処理の制限</strong>: API から得たデータなど、実行時にしか分からない値に基づいてまったく新しいスタイルを生成することはできません。ただし、CSS 変数などの技術でほとんどの動的な場面を補えます。</li>
</ul>
<h2>結論</h2>
<p>ゼロランタイム CSS-in-JS は、従来の CSS-in-JS パラダイムを正しい方向へ戻す試みです。「開発時の体験」と「実行時のパフォーマンス」を巧みに分離し、両者の間で難しい妥協をする必要をなくします。最高のパフォーマンスと小さなバンドルサイズを求めるモダン Web アプリケーションにとって、ほぼ完璧なソリューションを提供します。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[ES2022 新機能の概要：Top-Level Await、.at() など]]></title>
            <link>https://blog.m1ng.space/ja/posts/es/es2022-features-overview/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/es/es2022-features-overview/</guid>
            <pubDate>Fri, 15 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[ECMAScript 2022（ES2022）が正式に公開され、実用的な新機能が数多く追加されました。本記事では Top-Level await や .at() メソッドなど、特に注目すべき更新を短時間で紹介します。]]></description>
            <content:encoded><![CDATA[<h2>はじめに</h2>
<p>TC39 委員会の年次リリースプロセスにより、JavaScript 言語は毎年進化を続けています。ECMAScript 2022（ES2022）には、開発者体験とコードの可読性を高めるための新機能が数多く追加されました。なかでも特に注目すべき機能を見ていきましょう。</p>
<h2>1. トップレベル <code>await</code></h2>
<p>これは ES2022 で最も期待されていた機能の一つです。従来、<code>await</code> キーワードは <code>async</code> 関数の内部でしか使用できませんでした。そのため、モジュールのトップレベルスコープで非同期処理を扱うのは不便で、通常は IIFE（即時実行関数式）で非同期コードを包む必要がありました。</p>
<p><strong>以前 👎:</strong></p>
<pre><code>// data.js
import { fetchData } from './api.js';

let data;
(async () =&gt; {
  data = await fetchData();
  // ... 只能在这里使用 data
})();

export { data }; // 导出时 data 还是 undefined
</code></pre>
<p><strong>現在（ES2022）👍:</strong></p>
<pre><code>// data.js
import { fetchData } from './api.js';

const data = await fetchData();

export { data }; // 模块会等待 await 完成后再被其他模块评估
</code></pre>
<p>トップレベル <code>await</code> は、モジュールの動的読み込みや依存関係の初期化といった場面を大幅に簡素化し、非同期コードをより直感的に書けるようにします。</p>
<h2>2. 配列／文字列のインデックスメソッド <code>.at()</code></h2>
<p>JavaScript で配列の最後の要素を取得するには、通常 <code>arr[arr.length - 1]</code> と書く必要があり、冗長で間違いも起こりやすいものでした。ES2022 では <code>.at()</code> メソッドが導入され、前方と後方のインデックスを統一的に扱えるようになりました。</p>
<p><code>.at()</code> メソッドは整数を受け取ります。正の数なら対応するインデックスの要素を返し、負の数なら末尾から数えます。</p>
<p><strong>以前 👎:</strong></p>
<pre><code>const arr = [1, 2, 3, 4, 5];
const lastElement = arr[arr.length - 1]; // 5
const secondToLast = arr[arr.length - 2]; // 4
</code></pre>
<p><strong>現在（ES2022）👍:</strong></p>
<pre><code>const arr = [1, 2, 3, 4, 5];
const lastElement = arr.at(-1); // 5
const secondToLast = arr.at(-2); // 4

// 同样适用于字符串
const str = 'hello';
console.log(str.at(-1)); // 'o'
</code></pre>
<h2>3. <code>Object.hasOwn(obj, prop)</code></h2>
<p>オブジェクトが継承されたものではなく独自のプロパティを持つか確認する際は、通常 <code>Object.prototype.hasOwnProperty.call(obj, prop)</code> を使用します。この書き方は非常に煩雑で、<code>Object.create(null)</code> で作られたオブジェクトなど、一部のケースでは問題が起こることもあります。</p>
<p><code>Object.hasOwn()</code> は、より短く信頼性の高い静的メソッドを提供します。</p>
<p><strong>以前 👎:</strong></p>
<pre><code>const obj = { a: 1 };
console.log(Object.prototype.hasOwnProperty.call(obj, 'a')); // true
console.log(Object.prototype.hasOwnProperty.call(obj, 'toString')); // false
</code></pre>
<p><strong>現在（ES2022）👍:</strong></p>
<pre><code>const obj = { a: 1 };
console.log(Object.hasOwn(obj, 'a')); // true
console.log(Object.hasOwn(obj, 'toString')); // false
</code></pre>
<h2>4. その他の注目すべき機能</h2>
<ul>
<li><strong>Error Cause</strong>: <code>Error</code> コンストラクタが、エラーの「原因」を指定するための第 2 引数を受け取れるようになり、より明確なエラーチェーンを構築しやすくなりました。<pre><code>try {
  // ...
} catch (err) {
  throw new Error('New error message', { cause: err });
}
</code></pre>
</li>
<li><strong>RegExp Match Indices（<code>/d</code> フラグ）</strong>: <code>/d</code> フラグを使用すると、正規表現の一致結果に各キャプチャグループの開始インデックスと終了インデックスも含まれます。</li>
</ul>
<h2>結論</h2>
<p>ES2022 の新機能は革新的な大変化ではありませんが、JavaScript の細部を磨き、開発者が長年抱えてきた多くの問題を解決し、コードをより簡潔で堅牢なものにします。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[Redux のボイラープレートに別れを？軽量な状態管理ライブラリ Zustand 詳解]]></title>
            <link>https://blog.m1ng.space/ja/posts/react/zustand-vs-redux/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/react/zustand-vs-redux/</guid>
            <pubDate>Sun, 10 Apr 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Redux の煩雑さに尻込みしていませんか？Zustand は Hooks ベースの、極めてシンプルな React 状態管理手法を提供します。本稿では中核的な使い方と設計思想を解説します。]]></description>
            <content:encoded><![CDATA[<h2>1. Redux の「悩み」</h2>
<p>Redux が React エコシステムで最も有名かつ強力な状態管理ライブラリであることに疑いはありません。単方向のデータフローやタイムトラベルデバッグなどの特性により、大規模で複雑なアプリケーションでは信頼できる選択肢です。しかし、多くの小・中規模プロジェクトにとって、Redux の「ボイラープレート（Boilerplate）」は悩みの種になりがちです。</p>
<ul>
<li><strong>Actions &amp; Action Creators</strong>: 大量の action の型と作成関数を定義します。</li>
<li><strong>Reducers</strong>: 異なる action を処理するため、大規模な <code>switch</code> 文を記述します。</li>
<li><strong>Dispatch &amp; Selectors</strong>: コンポーネント内で <code>dispatch</code> によって action を送り、<code>useSelector</code> で状態の変化を購読します。</li>
<li><strong>Context Provider</strong>: アプリケーションのルートを <code>&lt;Provider&gt;</code> で包む必要があります。</li>
</ul>
<p>そのため、単純な状態を一つ追加するだけでも複数のファイルを変更する必要があり、手順が煩雑になります。</p>
<h2>2. Zustand：新鮮な選択肢</h2>
<p>Zustand（ドイツ語で「状態」）は、<code>react-three-fiber</code> の作者である Poimandres チームが開発した軽量な状態管理ライブラリです。その設計思想は<strong>ミニマル</strong>で<strong>非侵襲的</strong>であることです。</p>
<p><strong>中核的な特徴：</strong></p>
<ul>
<li><strong>コード量が非常に少ない</strong>: ある機能を実装するとき、Zustand のコード量は通常 Redux のごく一部です。</li>
<li><strong>Hooks ベース</strong>: すべてが 1 つのカスタム Hook を中心に構成されており、現代的な React 開発の習慣に沿っています。</li>
<li><strong>Context Provider が不要</strong>: アプリケーションの上層を Provider で包む必要はありません。Store はコンポーネントツリーから独立し、どこからでもインポートして利用できます。</li>
<li><strong>習得が容易</strong>: API が非常にシンプルで、中核的な使い方を数分で学べます。</li>
</ul>
<h2>3. 中核的な使い方</h2>
<p>Zustand の利用は、<strong>Store の作成</strong>と<strong>コンポーネントでの利用</strong>という 2 つの手順に分かれます。</p>
<h4>a. Store を作成する</h4>
<p>store はどの <code>.js</code> または <code>.ts</code> ファイルにも定義できます。</p>
<pre><code>// src/store.js
import { create } from 'zustand';

const useBearStore = create((set) =&gt; ({
  bears: 0,
  increasePopulation: () =&gt; set((state) =&gt; ({ bears: state.bears + 1 })),
  removeAllBears: () =&gt; set({ bears: 0 }),
}));

export default useBearStore;
</code></pre>
<p><code>create</code> 関数はコールバックを受け取り、その引数が <code>set</code> 関数（React の <code>setState</code> に似た関数）です。ここで状態と、状態を更新するメソッドを定義します。</p>
<h4>b. コンポーネントで利用する</h4>
<p>どのコンポーネントでも、通常の Hook と同じように使えます。</p>
<pre><code>// src/components/BearCounter.jsx
import useBearStore from '../store';

function BearCounter() {
  const bears = useBearStore((state) =&gt; state.bears);
  return &lt;h1&gt;{bears} around here ...&lt;/h1&gt;;
}
</code></pre>
<p>セレクタ関数 <code>(state) =&gt; state.bears</code> を使い、<code>bears</code> の状態を購読している点に注目してください。これにより、コンポーネントは <code>bears</code> が変化したときだけ再レンダリングされるため、不要なパフォーマンスコストを避けられます。</p>
<pre><code>// src/components/Controls.jsx
import useBearStore from '../store';

function Controls() {
  const increasePopulation = useBearStore((state) =&gt; state.increasePopulation);
  return &lt;button onClick={increasePopulation}&gt;one up&lt;/button&gt;;
}
</code></pre>
<p>action の取得も同じように簡単です。</p>
<h2>4. 非同期 Action</h2>
<p>Zustand は非同期処理も非常に自然に扱えます。<code>redux-thunk</code> や <code>redux-saga</code> のようなミドルウェアは必要ありません。</p>
<pre><code>const useAsyncStore = create((set) =&gt; ({
  data: null,
  fetchData: async (url) =&gt; {
    const response = await fetch(url);
    const data = await response.json();
    set({ data });
  },
}));
</code></pre>
<h2>まとめ</h2>
<p>Zustand は Redux を完全に置き換えようとするものではありません。厳格な規約、追跡可能性、巨大なエコシステムという点では、Redux に今も優位性があります。</p>
<p>しかし、大多数の React アプリケーションにとって、Zustand はよりシンプルかつ高速で、認知的な負担が少ない選択肢を提供します。Redux の煩雑な手続きに疲れている場合や、次のプロジェクトで軽快かつ柔軟な状態管理ライブラリが必要な場合、Zustand は間違いなく試す価値のある優れた選択肢です。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[TurborepoでMonorepoプロジェクトを管理する]]></title>
            <link>https://blog.m1ng.space/ja/posts/build-tools/intro-to-turborepo/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/build-tools/intro-to-turborepo/</guid>
            <pubDate>Sun, 20 Feb 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[プロジェクトが複雑になるにつれ、Monorepoは一般的なコード構成方法になりました。しかし、それに伴うビルド性能の問題をどう解決すればよいのでしょうか。Turborepoは、まさにそのために生まれた高性能ビルドシステムです。]]></description>
            <content:encoded><![CDATA[<h2>1. なぜMonorepoを選ぶのか？</h2>
<p>Monorepo（単一コードリポジトリ）は、複数の独立したプロジェクトやパッケージを1つのコードリポジトリに保存する戦略です。各プロジェクトが個別のリポジトリを持つPolyrepo方式と比べて、Monorepoにはいくつかの大きな利点があります。</p>
<ul>
<li><strong>コード共有</strong>：異なるプロジェクト間でコンポーネント、ユーティリティ関数、型定義を非常に簡単に共有できます。</li>
<li><strong>アトミックなコミット</strong>：1つの機能変更が複数のパッケージに関係する場合でも、1回のコミットで完了でき、バージョンの一貫性を保てます。</li>
<li><strong>依存関係管理の簡素化</strong>：すべてのプロジェクトが1つの<code>node_modules</code>を共有するか、pnpm/yarn workspaceで最適化するため、依存関係の競合やバージョンの不一致を減らせます。</li>
</ul>
<p>しかしリポジトリが大きくなると、Monorepoには<strong>ビルド性能</strong>という課題も生じます。</p>
<h2>2. Monorepoの悩み</h2>
<p>リポジトリに<code>docs</code>、<code>webapp</code>、そして共有の<code>ui</code>コンポーネントライブラリがあると想像してください。<code>docs</code>の誤字を1つ直しただけなのに、<code>webapp</code>や<code>ui</code>を含むリポジトリ内の全プロジェクトが再ビルド、再テストされることは最も避けたいはずです。</p>
<p>Lernaなど従来のMonorepo管理ツールは、タスクのオーケストレーションやビルドキャッシュに不十分な点があり、次の問題につながります。</p>
<ul>
<li><strong>作業の重複</strong>：コードの大部分が変わっていなくても、CI/CDを実行するたびにすべてを最初からビルドし、テストします。</li>
<li><strong>長いビルド時間</strong>：複数のCPUコアを活用してタスクを効率よく並列実行できません。</li>
<li><strong>複雑なスクリプト</strong>：タスクの実行順序を手動で制御するために、複雑な<code>package.json</code>スクリプトを書く必要があります。</li>
</ul>
<h2>3. Turborepo：速度のために生まれた</h2>
<p>TurborepoはJavaScript/TypeScriptのMonorepo向けに設計された高性能ビルドシステムで、後にVercelに買収されました。<strong>増分ビルド</strong>と<strong>リモートキャッシュ</strong>という2つの中核技術で、上記の問題を解決します。</p>
<h4>a. 増分ビルドとタスクパイプライン</h4>
<p>Turborepoでは、ルートの<code>turbo.json</code>ファイルでタスク間の依存関係を定義できます。</p>
<pre><code>// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": []
    },
    "lint": {
      "outputs": []
    },
    "dev": {
      "cache": false
    }
  }
}
</code></pre>
<ul>
<li><strong><code>dependsOn: ["^build"]</code></strong>：<code>^</code>記号は、あるパッケージの<code>build</code>タスクが、そのパッケージの依存先にあるすべての<code>build</code>タスクに依存することを意味します。Turborepoはこのグラフに基づき、最も効率的な並列順序でタスクを実行します。</li>
<li><strong><code>outputs</code></strong>：そのタスクがどの出力ファイルを生成するかをTurborepoに伝えます。</li>
</ul>
<p><code>pnpm turbo build</code>を実行すると、Turborepoは変更されたファイルを計算し、影響を受けたパッケージだけを再ビルドします。パッケージのソースコードと依存関係が変わっていなければ、Turborepoは前回のビルド成果物をそのまま使うため、処理は一瞬です。</p>
<h4>b. リモートキャッシュ</h4>
<p>これはTurborepoの「キラー機能」です。ローカルマシンにビルド結果をキャッシュするだけでなく、Vercelや独自のS3バケットなど、共有リモートサーバーへキャッシュをアップロードできます。</p>
<p>つまり、次のことが可能です。</p>
<ul>
<li><strong>同僚</strong>が最新のコードを取得した後、その人が必要とする部分をあなたがすでにビルドしていれば、ローカルで再ビルドせずにキャッシュを直接ダウンロードできます。</li>
<li><strong>CI/CDサーバー</strong>もこのリモートキャッシュに接続できます。あるPRがCIでビルドされキャッシュされれば、他の開発者や後続のCIタスクがその成果をすぐに利用できます。</li>
</ul>
<p>これにより、チーム全体のビルド時間を数十分から数分、さらには数十秒まで短縮できます。</p>
<h2>結論</h2>
<p>TurborepoがMonorepoを発明したわけではありませんが、高度なキャッシュとタスクスケジューリングシステムを導入することで、Monorepoの開発体験を大幅に改善し、最も重要な性能上のボトルネックを解決しました。Monorepoアーキテクチャを使用している、または採用を考えているなら、Turborepoはあなたとチームの多くの時間を節約できる強力なツールです。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[SolidJS：真にリアクティブな JavaScript フレームワーク]]></title>
            <link>https://blog.m1ng.space/ja/posts/frameworks/introduction-to-solidjs/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/frameworks/introduction-to-solidjs/</guid>
            <pubDate>Fri, 05 Nov 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[React のように見えますが、仮想 DOM はありません。SolidJS は革新的な細粒度リアクティブシステムによって、新たな水準のパフォーマンスを実現します。その仕組みを見てみましょう。]]></description>
            <content:encoded><![CDATA[<h2>1. フロントエンドフレームワークの「聖杯」：パフォーマンスと体験</h2>
<p>React が仮想 DOM（Virtual DOM）を普及させて以来、VDOM はモダンなフロントエンドフレームワークの標準装備になったかのようです。メモリ上に仮想的な UI 表現を保持し、diff アルゴリズムで最小限の DOM 更新を計算することで、開発体験と多くの場面でのパフォーマンスを向上させます。</p>
<p>しかし、VDOM にコストがないわけではありません。それ自体がメモリを消費し、diff 処理にも計算コストがかかります。そこで一つの疑問が生まれます。VDOM を介さず、状態の変化を DOM に直接かつ正確に反映しながら、宣言的で React に似た開発体験を維持できるのでしょうか。</p>
<p>SolidJS はその答えを示しています。</p>
<h2>2. SolidJS の核心：細粒度リアクティビティ（Fine-Grained Reactivity）</h2>
<p>SolidJS は宣言的でリアクティブな JavaScript フレームワークです。JSX を使用するため React とよく似ていますが、その内部原理はまったく異なります。</p>
<p>SolidJS のコンパイラは JSX コードを最適なネイティブ DOM 操作へ変換します。VDOM は使用せず、リアクティブな「シグナル」（Signals）で構成される依存グラフを作ります。シグナルの値が変わると、そのシグナルを購読している「エフェクト」（Effects）または計算（Memos）だけが再実行されます。</p>
<p><strong>常識を覆すメンタルモデル：コンポーネントは一度しか実行されない！</strong></p>
<p>React では state や props が変化すると、コンポーネント関数全体が再実行されます。しかし SolidJS では、コンポーネント関数は <strong>最初から最後まで一度しか実行されません</strong>。</p>
<pre><code>import { createSignal } from 'solid-js';

function Counter() {
  console.log('Component function runs!'); // 这句话只会在组件挂载时打印一次

  const [count, setCount] = createSignal(0);

  const increment = () =&gt; setCount(count() + 1);

  return (
    &lt;button type="button" onClick={increment}&gt;
      Count: {count()}
    &lt;/button&gt;
  );
}
</code></pre>
<p>ボタンをクリックすると、<code>count()</code> シグナルの読み取り部分と、それに依存する DOM テキストノードだけが更新されます。<code>Counter</code> 関数自体は再実行されません。この「外科手術のような」更新こそが、SolidJS の卓越したパフォーマンスの源です。</p>
<h2>3. 主要 API</h2>
<p>SolidJS のリアクティブシステムは、主に三つの基本プリミティブで構成されています。</p>
<ul>
<li><strong><code>createSignal(initialValue)</code></strong>: リアクティブなシグナルを作成し、getter と setter を返します。<code>[count, setCount]</code></li>
<li><strong><code>createEffect(() =&gt; {})</code></strong>: 「エフェクト」を作成します。内部で読み取られたすべてのシグナルを自動的に追跡し、そのいずれかが変化すると再実行されます。DOM を手動で操作するなどの副作用に適しています。</li>
<li><strong><code>createMemo(() =&gt; {})</code></strong>: キャッシュされる派生計算値を作成します。内部で依存するシグナルが変化したときだけ再計算されます。</li>
</ul>
<pre><code>import { createSignal, createEffect } from 'solid-js';

function App() {
  const [firstName, setFirstName] = createSignal('John');
  const [lastName, setLastName] = createSignal('Smith');

  // createEffect 会在 firstName 或 lastName 变化时自动运行
  createEffect(() =&gt; {
    console.log(`Full name: ${firstName()} ${lastName()}`);
  });

  // ...
}
</code></pre>
<h2>4. SolidJS を選ぶ理由</h2>
<ul>
<li><strong>卓越したパフォーマンス</strong>: さまざまな独立ベンチマークで SolidJS は上位に入ることが多く、ネイティブ JavaScript コードに非常に近い性能を示します。</li>
<li><strong>非常に小さなバンドルサイズ</strong>: VDOM ランタイムがないため、コアパッケージは非常に小さくなっています。</li>
<li><strong>慣れ親しんだ開発体験</strong>: React Hooks に慣れていれば、SolidJS をすぐに使い始められます。JSX とリアクティブプリミティブの組み合わせは強力で直感的です。</li>
<li><strong>真のリアクティビティ</strong>: そのモデルは MobX や Vue の Composition API に近いものですが、コンパイラによって実行時コストなしで実現されています。</li>
</ul>
<h2>結論</h2>
<p>SolidJS はフロントエンドフレームワークの進化における重要な方向性を示しています。つまり、コンパイラによってビルド時により多くの処理を行い、実行時コードを減らしてパフォーマンスを高めるという方向です。宣言的な開発体験を犠牲にせず、仮想 DOM の制約から完全に離れられることを証明しています。最高のパフォーマンスを求めるアプリケーションにとって、SolidJS は非常に魅力的な選択肢です。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
        <item>
            <title><![CDATA[Fetch を本当に使いこなせていますか？AbortController によるリクエストのキャンセル]]></title>
            <link>https://blog.m1ng.space/ja/posts/javascript/fetch-with-abortcontroller/</link>
            <guid isPermaLink="false">https://blog.m1ng.space/ja/posts/javascript/fetch-with-abortcontroller/</guid>
            <pubDate>Sat, 25 Sep 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[現代の Web 開発では、Fetch API が HTTP リクエストを行う標準的な手段になっています。しかし、不要になったリクエストを適切にキャンセルする方法をご存じでしょうか。その答えが AbortController です。]]></description>
            <content:encoded><![CDATA[<h2>1. Fetch API：現代の Web リクエストの基盤</h2>
<p><code>Fetch API</code> は古い <code>XMLHttpRequest</code> に代わり、ブラウザで HTTP リクエストを行う標準的な手段になりました。Promise を基盤とし、より簡潔で強力なリクエスト機能を提供します。</p>
<p>しかし、<code>Fetch API</code> には標準でリクエストを直接キャンセルする仕組みがありません。多くの場面で、リクエストのキャンセルは非常に重要です。</p>
<ul>
<li><strong>パフォーマンスの最適化</strong>: ユーザーがページを素早く切り替えたり検索語を入力したりするとき、古くなって不要になったリクエストをキャンセルすれば、帯域幅とサーバー資源を節約できます。</li>
<li><strong>競合状態の回避</strong>: 「入力しながら検索」する場面では、古いリクエストが新しいリクエストより遅く返ると、UI に古いデータが表示される可能性があります。</li>
<li><strong>メモリリークの防止</strong>: コンポーネントのライフサイクル内で開始したリクエストが完了する前にコンポーネントがアンマウントされると、存在しないコンポーネントを更新しようとしてエラーやメモリリークが起きる可能性があります。</li>
</ul>
<h2>2. <code>AbortController</code>：汎用的なキャンセルシグナル</h2>
<p><code>AbortController</code> は、1 つまたは複数の Web リクエストを中止する仕組みを提供する汎用的な Web API です。<code>Fetch API</code> とは独立していますが、<code>Fetch</code> と完全に連携できます。</p>
<p><code>AbortController</code> の基本的な考え方は次のとおりです。</p>
<ol>
<li><code>AbortController</code> のインスタンスを作成します。</li>
<li>そのインスタンスから <code>AbortSignal</code> オブジェクトを取得します。</li>
<li><code>AbortSignal</code> を、<code>fetch</code> など中止可能な Web API に渡します。</li>
<li>キャンセルが必要になったら、<code>AbortController</code> インスタンスの <code>abort()</code> メソッドを呼び出します。</li>
</ol>
<h2>3. <code>AbortController</code> と <code>Fetch</code> の組み合わせ</h2>
<p>例を通して、<code>AbortController</code> で <code>Fetch</code> リクエストをキャンセルする方法を見てみましょう。</p>
<pre><code>const controller = new AbortController();
const signal = controller.signal; // 获取信号对象

async function fetchDataWithCancellation(url) {
  try {
    console.log('Fetching data...');
    const response = await fetch(url, { signal }); // 将信号传递给 fetch
    const data = await response.json();
    console.log('Data received:', data);
    return data;
  } catch (error) {
    if (error.name === 'AbortError') {
      console.log('Fetch request was aborted.');
    } else {
      console.error('Fetch error:', error);
    }
  }
}

// 示例用法
const promise = fetchDataWithCancellation('https://jsonplaceholder.typicode.com/posts/1');

// 假设在 500 毫秒后，我们决定取消这个请求
setTimeout(() =&gt; {
  controller.abort(); // 调用 abort() 方法取消请求
  console.log('Request aborted by timeout.');
}, 500);
</code></pre>
<p><code>controller.abort()</code> が呼び出されると、<code>fetch</code> リクエストは直ちに中止され、<code>AbortError</code> がスローされます。このエラーを <code>catch</code> ブロックで捕捉し、<code>error.name === 'AbortError'</code> を確認することで、キャンセル操作とその他のネットワークエラーを区別する必要があります。</p>
<h2>4. 実際の利用場面</h2>
<h4>a. 入力しながら検索（Search-as-you-type）</h4>
<p>ユーザーが検索ボックスへ素早く入力すると、入力のたびに新しいリクエストが発生する可能性があります。直前の未完了リクエストをキャンセルし、最新のリクエストだけを残せます。</p>
<pre><code>let currentController = null;

document.getElementById('searchInput').addEventListener('input', (event) =&gt; {
  if (currentController) {
    currentController.abort(); // 取消上一个请求
  }
  currentController = new AbortController();
  const signal = currentController.signal;

  const query = event.target.value;
  if (query.length &gt; 2) {
    fetchDataWithCancellation(`/api/search?q=${query}`, signal);
  }
});
</code></pre>
<h4>b. コンポーネントのアンマウント時にリクエストをキャンセル</h4>
<p>React や Vue などのフレームワークでは、コンポーネントがアンマウントされるときに、その内部で開始した未完了のリクエストをキャンセルすることで、メモリリークや不要な UI 更新を効果的に防げます。</p>
<pre><code>// React 示例
useEffect(() =&gt; {
  const controller = new AbortController();
  fetchDataWithCancellation('/api/data', controller.signal);

  return () =&gt; {
    controller.abort(); // 组件卸载时取消请求
  };
}, []);
</code></pre>
<h2>まとめ</h2>
<p><code>AbortController</code> は現代の Web 開発に欠かせないツールです。<code>Fetch API</code> やその他の非同期処理にネイティブなキャンセル機構を提供し、より堅牢で効率的、かつ優れたユーザー体験を持つアプリケーションの構築に役立ちます。<code>AbortController</code> の使い方を身につけることは、優れたフロントエンド開発者になるために必要なスキルの一つです。</p>
]]></content:encoded>
            <author>m1ngsama</author>
        </item>
    </channel>
</rss>