プライベートメソッドをテストするのかの話
時々目にするプライベートメソッドのテストの話題
久々にまた見かけたので
テストすべきかどうかよりしたいかどうかだと思います

個人的にはクラスをほぼ使わないのでモジュールに置き換えます
モジュールが公開する関数と公開しない関数があって公開しない関数もテストするかです

少し極端なケースですが 2 つの非公開関数と 1 つの公開関数があるとします
非公開関数の片方は外部からデータを取得するもので もう片方はデータをフォーマットするものです
公開関数はこれらを組み合わせたものです

もう少し具体的な例

const getData = (opt) => {
// ...
}
const formatData = (data, opt) => {
// ...
}

export default (opt) => {
return formatData(getData(opt), opt)
}

こういうときに公開されてる関数だけで多くのパターンをテストするのって大変です
getData がデータベースや API やファイルからデータを取得する場合は フォーマットのテストのために毎回データを取得しないといけないです
そうなると 1 回 1 回の処理が遅くなります
getData と formatData をそれぞれテストすればフォーマットのテストのために毎回データの取得は不要です

中の処理がわかっていれば それをモックに置き換えることもできます
getData が API を呼び出すなら fetch を置き換えたり Service Worker 使うなどして 実際のリクエストを避けつつ公開関数を使って formatData をテストできます
でも面倒ですし formatData を直接テストすれば不要な苦労をしています

こういう場合や非公開関数に複雑なロジックがあればそこだけは単体でテストしておきたいです
非公開関数がたいしたことをしてなくて公開関数を数パターンテストすれば十分ってレベルならわざわざ非公開の関数までテストする必要ないと思います

まぁ JavaScript の場合はモジュール内の非公開関数や class のプライベートプロパティ機能で隠されたものはアクセスできないのでテストするのが難しいのですけどね
__privates みたいな名前でオブジェクトをエクスポートして 環境がテストなら非公開の関数を全部このオブジェクトに追加とか考えましたが そこまでするのもどうなのという気持ちです
こういうテストを考えると Python みたいな全部オープンの方針の方が助かるのですけどね
実際に動かす上で不要な処理であるテストのためにコードを書き換えるのはできるだけ避けたいですし
input と textarea のフォント
input や textarea のフォントってどうするのがいいんでしょうか

デフォルトを見てみると input と textarea では異なるようです
またブラウザでも異なります

Windows 環境で Chrome/Edge (117) を見ると

input:
  ユーザーエージェントの font-family: 空
  表示されるフォント: Arial, Meiryo

textarea:
  ユーザーエージェントの font-family: monospace
  表示されるフォント: MS Gothic

Windows 環境で Firefox (118) を見ると

input:
  ユーザーエージェントの font-family: MS Shell Dlg 2
  表示されるフォント: tahoma, Meiryo

textarea:
  ユーザーエージェントの font-family: monospace
  表示されるフォント: consolas, MS Gothic



どちらも等幅かと思ったら input はそうではないようでした
また等幅フォントのデフォルトはギザギザして汚い MS Gothic でした

monospace で表示されるフォントはブラウザの設定で変えることができ 私は別フォントにしてたので全然気づいてませんでしたが 設定してないブラウザでみるとすごく残念な画面になってました
(Chrome のフォント設定画面は chrome://settings/fonts)
基本的にはデフォルトのものにしておきたいですが さすがにこれは汚すぎで見るに堪えないです
変えておこうかなと思っても標準フォントで等幅ってこれといったのが思いつかないです

UI ライブラリの入力コンポーネントや世の中のページを見てると そもそも等幅にしてるところがそんなに多くないようでした
等幅にしているところはだいたいウェブフォントで独自のフォントを使っているようです
可変幅のところでは inherit にして親と一緒 つまり div や p などの通常のテキストと同じフォントにしてるのを見かけました
また input と textarea でフォントを分けず まとめて同じ可変幅のフォントを設定していたりです
たしかに分ける必要って特に無いと思いますし 等幅じゃなくて困ったということもありません

とりあえず本文と同じ Meiryo でいいかなと思いました



この考えでいくと テキストエディタも可変幅でも良さそうに思えてきました
プログラムで 「=」 や 「:」 や 「//」 の位置など 行頭以外の場所を縦に揃えたがる人は抵抗がありそうですが 行頭以外は基本揃える必要ないって私からすると別に問題無い気もします
考えてみると 可変幅になってる textarea でコードを書くことって普通にあります
「見直してみたら可変幅だね ここ」 くらいに気にしてなかったです
また 日本語がない半角フォントが設定されていて 半角のみ等幅になっていて 日本語が入ると可変幅になるところもありました
フォントの違いが気になりはしますが 一時的なところなら実害はないので放置でした

VSCode のフォントを Meiryo にしてもいいかななんて思いましたが 考えてみたらプログラミング用フォントは等幅なだけではなく 紛らわしい文字の差別化もしてくれてるのですよね
やっぱりプログラミング用フォントを使うのが無難そうです

他には 等幅のほうがパフォーマンス的にも優れてそうな気はしました
文字関係なく幅が固定のほうが事前にサイズ計算ができて重たいファイルを開いて画面に表示するときは差が出そうです
と思いましたが等幅でも半角全角が存在しますし 絵文字みたいなところでは完全に等幅になっていないです
それらも考慮しないといけないので あまり変わらないかもです

あとは 矩形選択したいようなものを扱うときでしょうか
ただこれはマルチカーソル機能があればそっちのほうが高度なので 重要でないかもしれません

どちらかというと SQL の結果など 表形式のテキストを貼り付けてきれいに見えないほうが困りそうです
インストールするソフトが減ってる
Chrome が勝手に Youtube や GoogleDrive のアプリ (Chrome を開くだけのリンク) を Windows PC にインストールしたようで Windows メニューの最近の追加のところに出てきていたので消しました
そのときインストール済みプログラム一覧のページに飛んだのですが リストの内容が思ってたより少なかったです
この PC はもう 1 年以上使ってるのですけど スクロールせずに収まるほど
昔はけっこうな量が並んでいたので 時代は変わったなと思います
最近は何するにもブラウザだけでほぼ終わりますからね

もしかすると ストアアプリのほうが増えてるのかも と思いもしましたが 数はありましたがデフォルトでインストールされてるもので使わないものばかりでした

今のところ自分でインストールして使ってるものはこれくらいです

ブラウザ
    Chrome
 
テキストエディタ
    VSCode

IME
    Google 日本語入力

キーボードユーティリティ
    AutoHotKey

アーカイバー
    7-Zip

画像ビュワー
    IrfanView

ペイント
    Paint.NET

その他
    WSL
    Node.js



以前は軽量のテキストエディタとしてサクラエディタを入れてましたが PC の性能が高めでメモリも十分に余ってれば VSCode で十分かなと この PC では入れてないです
ただ VSCode はフォルダを開く概念があるので プロジェクトに属さないテキストを見たり編集したりするときは少し扱いづらくて シンプルなテキストエディタを別に入れておいてもいいかなという気はしてます

Google 日本語入力は 入れなくても標準ので大丈夫かもと思って試してみましたが 無理でした
標準のは使いづらすぎな上にいい感じの予測変換が出てきてくれません
予測変換に大きく頼ってる自分としては必須なものでした
また 「今日」 と打って日付が出たり 「zh」 で 「←」 が出たり 郵便番号から住所が出たり と言った隠し便利機能も Google 日本語入力のほうが充実してます

画像の表示は Windows10 から標準のアプリが重たくなり さらに写真向けなのかスクショみたいなものの等倍表示がきれいに表示されなかったりで微妙なんですよね
以前は Windows7 の頃のビュワーに戻してましたが それなら軽量で高機能なフリーソフトを使ったほうがいいかと思って IrfanView を入れるようになりました
Windows11 では標準のビュワーが改善されてるのでしょうか

ペイントソフトは標準のが使いづらいので昔から Paint.NET にしています
リサイズ・トリミング・フォーマットの変更くらいなら問題ないのですが 中身をいじったり色を調整したりオブジェクトを切り抜いたりしようとすると機能不足感が強いです
本体はシンプルでプラグイン任せが強いソフトで 昔は色々なプラグインがありましたが 度重なるプラグインの互換性をなくすメジャーアップデートでほとんどが使えなくなりました
Firefox の拡張機能みたいな状態ですね
追従している作者のプラグインでも新しいバージョンで動作が変わっていて求めてるのは古いバージョンだったりすることもあり 昔できていたことができなくなっていたりします
GIMP 等への乗り換えを検討中

プログラミング言語系は WSL 内に入れることが多いですが Node.js のみ Windows にも入れています
Windows 側で動かしたいことが多めなのと Node.js は PHP などより Windows/Linux の差が少なく Windows 側に入れて動かすのに抵抗が少なめです

この PC では Windows Terminal や新しい PowerShell は入れてないです
VSCode のターミナル機能があれば 勝手に落ちてる Windows Terminal はなくてもいいかなという思いで Windows Terminal は入れませんでした
PowerShell はなんだかんだ古い方で困ってないので 必要なったら入れればいいかと思って入れてないままです
条件つきメソッドチェインしたい
最近はメソッドチェインを長く書くようなライブラリをあまり使うことがなかったのですが 久々につかうとやっぱりチェインに条件をつけたくなります

こういうの

const val = new A()
.method1()
.method2() // ← flag が true のときだけ追加したい
.method3()

ライブラリによっては考慮されていて チェイン内で分岐できるようなメソッドがあったりします
しかし分岐したいなら変数にいれて if を使ってというスタンスのライブラリもあります
そうするとメソッドチェインできれいに書けるメリットが失われます

JavaScript の機能が増えてきているといってもやっぱりこういうのはいい方法がないです
ありがちなのがラップして独自の分岐メソッドを追加する方法

const val = $(new A())
.method1()
.$(flag, $ => $.method2())
.method3()
.unwrap()

しかし method1 などはラップしたオブジェクトが持っていないので Proxy が必要になります
また最後にアンラップして中身を取り出さないといけないです
このタイプは過去何度か作ってみても 利便性のいまいちさや Proxy に抵抗があって実際には使ってないのですよね

全てのオブジェクトにメソッドを追加する prototype 拡張がもっとシンプルになるのですが prototype 拡張は積極的に使うのはどうかなというところです
特に全てに影響する Object.prototype ですし

ただ キーがシンボルなら 影響はほぼなさそうですし ありなのかなと思ったり

const val = new A()
.method1()
[chain_if](flag,
$ => $.method2(),
)
.method3()

チェインの記法がちょっと変わるのが専用構文ぽくて ひとつ上の例よりは好きかもしれないです

動かす用のサンプル

Object.prototype[Symbol.for("if")] = function(cond, fn) {
if (cond) {
return fn(this)
} else {
return this
}
}

class A {
arr = []
method1() {
this.arr.push(1)
return this
}
method2() {
this.arr.push(2)
return this
}
method3() {
this.arr.push(3)
return this
}
}

const flag = true // or false
const val = new A()
.method1()
[Symbol.for("if")](flag,
$ => $.method2(),
)
.method3()

console.log(val)
state と input のフォーマットをどこで揃えるか
DOM 外に state としてフォームの入力を保持する系ライブラリを使うとき今でも迷うところ

input は基本 値を文字列で扱います
type が number とか date でも value は文字列です
一応 valueAsNumber とか valueAsDate とかありはしますが 扱いづらいところがあるのでこれらは使いません
state 側では数値や Date 型など文字列以外で持っていることも少なくないです

そういうときにどうするかです

ひとつは input の入出力の際に毎回変換することです
value に渡すときに文字列に変換して 変更のイベント時に文字列から state の型に変換して state を更新します
それぞれの input の受け渡しのコードが長くなるのと 都度変換が必要なところが微妙です
日付型を文字列にフォーマットするくらいなら パフォーマンスに影響することはほとんどないと思いますが ユーザーの入力のたびにやるのってとてもムダに思えます
また 一度の再レンダリングで全部の input 分の変換を行うので 数が多い場合はパフォーマンスに影響無いとも言い切れないです
それに input は input そのものじゃなくてコンポーネントになってることもあります
その場合は変換がもっと重い処理のこともあります
別のオブジェクトを参照して内部の値を照合して とか

ベストな方法とは思えないなと思いつつ仕方ないか でやってる方法です

別の方法は フォーム用に state を用意するというものです
編集中として 編集開始時に state をコピーします
そのときそのままのコピーではなく input 用の表現に変換しておきます
そうすれば編集中 state は input と同じ型なので 編集中に変換不要です
state の値を そのまま input にセットして 変更後の値をそのまま state にセットできます
保存ボタンなど編集を完了するイベントで 編集中 state を本来の state に変換して更新します

変換は編集開始と終了の最小限なので こっちのほうが良さそうに思ってます
ただ state が増えるのはデメリットもあります
編集中に元 state が変わったときの扱いが難しくなります
全部新しい state で置き換えるならいいですが state 内の変更があったプロパティだけとなると自分で差分を見つけてそこだけを編集中 state に反映しないといけないので面倒です
React だと state 全体を更新だとしても変更を検知するための useEffect が必要になるのでローカル state を増やすこと自体が気が進まないです

また 編集中 state は基本的にそのフォーム内だけのものです
入力途中の state を参照したいとしてもほとんどの場合はそのフォーム内部の話です
なので問題なさそうに見えるのですが 稀にフォーム外の場所にも反映したいことがあります
例えば画面テーマの色を選べるとします
選んだ色をフォーム内でプレビューとして表示することができますが 実際にヘッダーとかサイドバーとかをその色にして確認したいなんてこともあります
そういうフォーム外にも編集中 state を反映したい場合は面倒が増えます

常にどっちの方がいいとは言えないので 未だにどっちにするか迷うところです
一応今のところは React は 1 つめの方法で lit (WebComponents) は 2 つめの方法にしてることが多めです

他にはフォームの機能によって変えてたりです
保存ボタンが存在しないフォームだと state を分けても都度 編集中 state を本来の state に反映することになって分ける意味がないです
なので 1 つめの方法です
キャンセルやリセットボタンがあるフォームなら 初期 state と編集中 state の 2 つを保持する必要があります
なので 2 つめの方法です
リセット機能はなく 保存ボタンだけがあるフォームだとどっちでもいいのでやっぱり迷います
ReactNative ってこれから流行るの?
以前は ReactNative が話題になることも結構あったと思うのですが 今ではほぼ見ることがないです
人気どころではなく Angular 的な使いたい人がひっそり使い続けるようなポジションになったと思ってます
比べて Flutter は Google のイベントで大々的に発表していて たまにニュースで見かけます
以前に比べてどんどん改善されていってるようですし クロスプラットフォームでモバイルをサポートするなら もう Flutter 一強かなと思ってました

しかし 最近ネットで見かけたものでは これから ReactNative が流行ると言ってる人がいました
昔の情報かなと思って日付を見たら今年の中頃でした
公式サイトを見てみてもこれといった大きな更新の発表もないですし そうは思えないのですけど
ReactNative が流行る理由があるのでしょうか

ウェブで React が流行ってると言っても ReactNative になると HTML や CSS は使えません
比較的に似てるコンポーネントは提供されていますが ウェブほど使いやすくないです
コンポーネントなど React の考え方が使えるくらいにしかメリットはないと思います
あと言語が JavaScript/TypeScript というところも Dart よりは良いのかもです

しかし ウェブを前提としたライブラリは使えませんし ReactNative ユーザーはウェブよりはるかに少ないのでライブラリもそれほど充実してるように思えません
あと React という名前のせいでウェブの情報が混ざっていたりして紛らわしいです

またあくまで View 部分のみしかやってくれないので ReactNative だけだと自分でネイティブレイヤーを制御しないといけないです
期待してるのは JavaScript だけですべて行えて Android や iOS の固有の知識が要らないものです
そうしようとすると Expo というのを使わないといけなくなりますが これもまた癖があります
それに更新が速すぎて全然安定してないので たまにしか使わないアプリを更新しようとしたら SDK のサポートが終わっていて SDK を更新するには変更点が多すぎます
Expo 機能のほんの一部しか使ってない場合でも影響範囲が多かったりです
ググってみてもこの辺が問題で 試しに作ってみる段階には使えても本番としては使えるものじゃない みたいな感想を目にします

それらが改善される何かが出たのかなと思って調べても特になにもないのですよね
何年も前の Chrome を使い続けてる会社がある?
アクセスログを眺めてたときのこと 異常にアクセス数が増えてるページがあって 生のログを見てみると同じユーザーから 10 回以上の連続したリクエストが来てました
詳細を見るとリファラなしの直接アクセスみたいで UA を見ると古い Chrome (80 くらい)
クローラーとか自動でアクセスしてきてるやつで UA をそのときの Chrome に設定したままなんだねーと思ってました

そんなこともあるかーで流しておこうとしたら 一番最後だけ UA が変わってるのに気づきました
ほぼ最新の iPhone から同じページへのアクセスです
見直してみると連続アクセスは機械的にリクエストしたにしてはタイムスタンプが奇妙です
1 秒に何回もあるわけではなく数秒おきでアクセスされていました
アクセス間隔は等間隔ではなくばらつきがあります

もしかして本当に古い Chrome を使って人がアクセスしていたのでしょうか
80 だと 3 年半ほど前のバージョンなので たぶんページが正しく表示できないと思います
表示されないのをサーバー負荷などの問題と思って何度もリクエストを繰り返して 最終的に諦めて iPhone からアクセスしたということなんでしょうか

アクセス元のドメインを見るとお堅そうな日本の会社でした
割りとあり得るかもしれない……

今の時代ブラウザは自動更新されるものなのに古いバージョンに固定なんてありえないですよね
IE が消えて 世の中のページも最新機能を取り入れるところが増えているので見れないページが多くなります
インターネットに接続せず社内システムを見るために使うというならまだわかりますが こっちのサイトにアクセスしてる以上 インターネットにつながってます
古いバージョンは脆弱性のパッチも当たってないのにそれでネットしてるって セキュリティ的にどうなの?って思います
開発者ツールで要素を確認しようとしたら要素が消えるときの対処方法
ポップアップで表示される部分の HTML 構造を確認したいとかありますよね
でも右クリックの「検証」を押したり devtools にフォーカスするとポップアップが閉じてしまうということがあります

原因は blur や focusout イベントを使って 要素がフォーカスを失ったらポップアップが閉じるようになっているから
devtools にフォーカスをあてるとページからはフォーカスが失われて このイベントが起きてポップアップが消えてしまいます

このためにけっこうな力技で対処していました

devtools の Elements タブですべての blur と focusout イベントのリスナを削除してから ポップアップを開きます
ポップアップの要素を消す処理が行われないので ポップアップは開いたままになります
本来の動作が行われなくなるので 確認後にリロードが必要です

別の手段では setTimeout で遅延して debugger を実行します
3 秒後に debugger を実行するようコンソールで実行してから 3 秒以内にポップアップを開きます
debugger が実行されると JavaScript の処理は実行されず固まるので ポップアップが開いたまま devtools を操作できます

こんな方法を使ってましたが 正当な方法がありました

devtools で Rendering タブを開きます
出てないならメニューの More tools から選択します
リストから「Emulate a focused page」を探してチェックを入れます
これでページにフォーカスが残るので devtools にフォーカスを当ててもポップアップは消えずに残ります

デフォルトで有効になってて欲しいくらいの機能です
コンポーネント関数と普通の関数
コンポーネントの関数って props を受け取って JSX の要素を返します
入出力は普通の関数と同じで 違うのはコンポーネント関数は React が呼び出して中でフックが使えるということ
普通の関数でフックを使うこともできますが それはフック関数という扱いになってフックのルールに則って使う必要があります

フックを使わないならコンポーネントにする必要がないようにも思います
例えば

{user && <UserInfo user={user} others={others}/>}

の代わりに

{user && UserInfo({ user, other }) }

と書いても動きます

そう思ったきっかけは逆で コンポーネント内で処理をまとめるために関数化していた部分があって 引数は 1 つのオブジェクトで JSX の要素が返ってくるものでした
これならコンポーネント化しても良さそうと思ったのですが むしろコンポーネントにする必要があるのかと疑問に思いました

コンポーネントだと React.memo が使えて props が同じなら再レンダリングを避けれます
ですが React.memo ってそんなに使うことがなくて 明らかに遅いようなところだけです
フックも使わないような小さいコンポーネントなので基本は memo しないものです

扱いやすさ的には普通の関数のほうが好きです
ただ その利点は React に依存しないという点が大きいですが フックを中で使わないなら命名規則くらいの差しかありません

見やすさ的には 上の例みたいに {} の中で使うならどっちもどっちですが そうでないなら普通の関数は実行するために必ず {} が必要になり 読みづらくなります
コンポーネントのほうが HTML ライクな記法で書けて見やすいです

迷うところですが 将来的にフックを使いたくなるかもと考えればとりあえず最初からコンポーネントにするのが無難かもしれないです

開発時に限れば コンポーネントにすると strict モードで複数回レンダリングされます
マウントされるコンポーネントが増えるほど重たくなります
普通の関数だとこれがないので少しですが速いです
本番ビルドには影響しないものなので これを理由に選ぶのはどうかとは思いますけど
セミコロン猛者
ちょっと前に見かけた JavaScript のセミコロンの話題
初心者だとどこに書けばいいのかわからない という話でした

たしかになくても動いてしまう以上 初心者はどこで必要なのか分かりづらい気がしますね
C や PHP など類似の構文でセミコロン必須の言語に触れたことがあれば そこではセミコロンが無いとエラーなのでちゃんとルールを把握してなくても使っていれば感覚で必須な場所はわかってきます
その流れで JavaScript を書いていれば セミコロンを文末に書く場合に必要な場所には困らないと思います
しかし JavaScript が初めてなら 要らないところにつけても 必要な場所につけなくても動きます
ちゃんと構文を理解してなければ難しそうです

基本は文末に書く と言っても if や for 文や関数宣言では不要です
セミコロンを書かない部分は 改行もセミコロンもなく 1 行にまとめて動く部分です

function a() {} a()

const a = function() {} a()

上は動きますが 下は構文エラーで動かないです
なぜかというと 上は関数宣言なので 「}」 が来るとそこで文の終わりと判断できます
なので自然と次のトークンの a は新しい文の始まりとわかります
下だと代入式なので 「}」 で文が終わるかは不明です
なので次のトークンの a も読み取ってみて ここで構文エラーになります

それならここで自動で文を分割してくれれば と思わなくもないですが 先を読んでみないとわからないのはパフォーマンスやパーサーの複雑度に影響しそうですし 構文エラーのバグが意図せず動いてしまうとかあるのでしょう

話を戻して 初心者にこういうところまで理解してというのは無理があると思います

構文チェックのツールやフォーマッターを使えば良いという意見もありそうです
ですが これも初心者がいきなり使うにはハードルがあるように思います
初心者というのは環境を準備というのが一番苦労するところです
JavaScript はメモ帳レベルのテキストエディタでも HTML を書いて script タグに JavaScript コードを書けばとりあえず動くという手軽さが魅力なのに こういうのの準備ってそういうメリットが失われますからね

なので個人的にはセミコロンは書かないほうがいいと思ってます
コード上入れるとしてもフォーマッターが入れて 人が書く必要はないと思います

ただその議論では予想外の方法を取ってる人がいました
すべての文にはセミコロンを入れるルールにしているようです
if や for のあとに入れても意味ないだけで別に問題ないですからね
たしかに統一感があり 迷うこともないので それならそれでいいんじゃないかなと思えました

こんな感じでしょうか

function a(value) {
if (value > 1) {
for (let i = 0; i< value; i++) {
console.log(foo(i));
};
} else {
console.log(value);
};
return {
foo: {
bar: {
baz: () => {
}
}
}
};
};

ただ最後に } が並ぶとき セミコロンなしのほうが全部が揃って見た目がきれいには思います

				}
}
}
}
}

意味が違う } でも全部一緒だとむしろ分かりづらいという考え方もできますが
React だとリアルタイム反映のほうがやりやすい
React などのライブラリを使わず DOM 操作で作ってるページだと なにかが変わったときにリアルタイムにあっちもこっちも反映って面倒です
だから確定ボタンを押したみたいなときに全体に反映させて それまでは外部に影響させないとか最小限の部分だけに反映させたりということが多いです

そうなってるものを動きを変えずに React で置き換えそうとすると 逆に面倒なんですよね
React だと state に持ってる情報から今の画面状態を作るので普通にやると全部が変わってしまいます
確定ボタンを押すまでは他に影響しないようにしたいなら 新たに state を用意する必要があります
グローバルの state と ローカルの state を用意して 普段はローカルの方だけを更新して ボタンが押されたらローカルをグローバルに反映するみたいなことになります
(グローバルと言ってもその state を使う範囲でのグローバルなのでページ内だったりタブ内だったりで プログラム的なグローバル変数というわけではないです)

React だと state 特にコンポーネントローカルの state はあまり増やしたくないのですよね
ローカルに state を持つことでそれを更新するための処理も必要になります
特に props や別フックの更新に応じて state を更新する必要があれば 変更を監視して更新するための useEffect もセットで必要になります

フォームや state 系のライブラリを見てみても 他の値の更新で state を更新する必要がある以上 どれもこの問題あるように思うのですが いい感じに解決できるものがあるのでしょうか
StackBlitz の Node.js のサーバーフレームワーク
StackBlitz で Backend 側テンプレートを見てると 見慣れないものがありました

Egg.js
https://github.com/eggjs/egg

Feathers
https://github.com/feathersjs/feathers

H3
https://github.com/unjs/h3

Nitro
https://github.com/unjs/nitro

ラインナップには Express や Koa はあるのに Hapi や Fastify はありません
それらよりもここにあるのは有名なのでしょうか?

ただ Egg.js と Feathers は言われてみると結構前にも見た覚えがなんとなくあります
2018 年か 2019 年くらいにフレームワークを探してたときだったかもです

たしか Egg.js は Koa を中で使ってて 中国でよく使われてるやつだったかと思います
Feathers はリアルタイム系らしいので WebSocket 系のようです
ソースコードを見てみると Socket.IO を使っていました

今でも StackBlitz のテンプレートに並ぶくらいには使われてるのでしょうか

H3 と Nitro は聞き覚えがないので新しいものかもしれません
リリース履歴をみるとどちらも去年からみたいなので新しいようです

H3 の方は Minimal H(TTP) framework らしく 小さめのライブラリみたいです
ミドルウェア系で Express/Koa に近い感じです
Router がついてるので Koa よりは高機能かもしれません
Express と Koa の違いみたいにハンドラで受け取るオブジェクトが異なっています
ただ Express と互換性のある形にもできるそうです
そうしないと Koa があまり流行らなかったみたいなことになりそうですからね

Nitro の方は Nuxt 関連のもののようです
Nuxt を強化できるらしいですが Nuxt なしでも使えるようで Nuxt を使う場合と使わない場合で設定の書き方が分かれてました

どれも今のところは特に使うことなさそうです
Effector
Stackblitz のテンプレートを見てると Effector というのを見つけました
ビジネスロジックを記述するためのライブラリだそうです
フレームワーク依存ではなく React/Vue/Solid で使えるようです

CounterEffects の例をみるとわかりやすいですが ロジックをコンポーネント外に書くことができて コンポーネントがスッキリするのがいいところみたいです

たしかにロジックはコンポーネントとは切り離したいですしね
でも実際はコンポーネント外でロジックを書くと面倒も多かったりします
フックで得られる値を参照できないので全部引数で渡す必要があったり
そのまま渡すとフックなどの API にロジック側が依存するので それを避けるなら間の層を設けないといけなくなったりします
なのでコンポーネント内に全部書いてしまうこともけっこうあって コンポーネントが大きくなりすぎて見づらい ってなったりします

このライブラリではその問題を解決してくれるようです

ですが 簡単な例を見る限りでは良さそうかも?と思うくらいでしたが複雑な例になってくるとコードもわかりづらくなってきます
そういうのを見てるとそこまでいいのだろうか?と疑問にも思えてきます
このライブラリを使うコード自体がパッと見てすごくわかりやすいとかシンプルにかけそうというのではなく 前提知識がないと難しそうなものですし

もっと知名度が出てユーザーも多くなってくれば考えますが現状だと使わないかなというところでした
Github のマルチアカウント
少しは涼しくなってきたし 転職活動でも再開しないとなぁとか思ってます
面倒だし考えるだけで憂鬱です(働きたくないでg

求人では ウチこういう技術使ってますよー とか書いてます
見てると Github を業務で使ってるところもあるようです
たしかにそういうところもあるよねー くらい思ってました

……が それに関連している ある書き込みを見かけました
個人ブログだったか Qiita みたいなプラットフォームだったか 場所まで正確に覚えてませんがこういう内容です
「ウチの会社では Github は個人アカウントを使うことにしています」

そういえば Github のアカウントは規約で複数アカウントを禁止しているから 仕事用と個人で同じのを使わないといけないという話題が何度かネットで話題になってましたね
話題に上がっても はっきりした結論はなく 問い合わせた返答で規約的にはダメというのと問題ないというのの両方あるらしくはっきりしない感じで終わってました

ググって出てきたのを見てる感じでは 仕事でも個人のを使わないといけないという主張は
「規約的にそう読める」
「(日本の?) Github で働いてる人に聞いた」

アカウントを分けて問題ないという主張は
「英語で本社に問い合わせたら問題ないと解答された」(複数あり)

のようです

問い合わせて問題ないと言われてるなら問題ないでいいと思います
普通に考えて 仕事で個人用アカウントを使うなんてありえないですし 仕事で個人のアカウントバレなんてもっとありえないです

コメントで見かけた
「アカウントを切り替えるのが面倒な人や 仕事でやったことも個人のコントリビュートにしたい人が 自分に都合良くしたいがためにそう広めてる」
というのがしっくりきました
英語圏ではそもそもこれが問題として議題に上がることもない(私が調べたわけではない)というのもこの説の信憑性感じられます

何にしても迷惑な話です
転職した先が個人アカウント使ってなんて方針だと 絶対お断りですが 事前にそういう情報がわからないというのも怖いですよね
Github を使ってるところは避けたほうが無難という気もしてきます
display: contents でラップするときの問題
display に contents を指定すると DOM のツリーとしては存在するのに存在しないように扱わせることができます
React の Fragment に近いイメージです
要素をまとめるための要素が存在するのに 無いものとして扱わせたいときに使います

例えば

<style>
.row {
display: flex;
}
</style>

<div class="row">
<div>A</div>
<div class="wrap">
<div>B</div>
<div>C</div>
</div>
<div>D</div>
</div>

div.row は display: flex なので横並びになりますが 2 つめの子要素は普通の div なのでここは縦並びになります

ABD
C

B と C を囲む div.wrap を無いものにしたいときは これに display: contents をつけます
これで

ABCD

という並びにできます
flex だと div.wrap も flex にすればいいのであまり必要なかもですが grid だともっと役立ちます

そんな display: contents ですが 完全に無いものとしては扱えず不便なときもあります
例えば 子要素にスタイルを当てるとき

<style>
.container > * {
margin-top: 10px;
}
.contents {
display: contents;
}
</style>

<div class="container">
<div>A</div>
<div class="contents">
<div>B</div>
<div>C</div>
</div>
<div>D</div>
</div>

こういうケースでは div.contents にマージンは効かず この div を透過して B と C にマージンが設定されることもありません
A と D にだけマージンが設定されます

React などをつかっていると div.container の子要素はコンポーネントで生成していて イベントをまとめて受け取るためなどで display: contents の要素でトップレベルをラップしてるとかもありえます
そうなるとこういう子要素に共通でスタイルを当てたいというときにうまく動かないケースが出てくるのですよね

CSS セレクタの > や + などでも display: contents は透過してくれるといいのですけど
ドット絵を拡大表示するときは image-rendering: pixelated
IE 時代と違って 画像の拡大縮小が起きても自動できれいに表示してくれるので ブラウザ上で画像を拡大縮小表示するときのアルゴリズムを気にすることは特になかったです
ですがドット絵を拡大するときはなめらかにされると微妙なことになるので そのままドット感を残して拡大してほしいです
IE 時代は CSS に独自プロパティがありましたが Chrome でもあるのかなと調べると image-rendering を使えば良いみたいです

元のサイズ

dots

拡大サイズ(通常)

dots-large

拡大サイズ(pixelated)

dots-large
React コンポーネントと値の初期化
今でもスッキリしない React での初期化処理の扱い方

const Component = (props) => {
// ...

return (
<div>
<Edit
value={value}
onChange={onChange}
/>
</div>
)
}

Edit コンポーネントがあって何かを編集するものです
React なので value を渡して編集があれば onChange で受け取って親側で更新するという 親側で state を管理する作りです
これだと value の値を初期化やチェックして修正するときに親側でやらないといけなくなります
ですが そのロジックは Edit のものなので Edit でやってもらいたいです
そうなると ユーザーの操作なしで Edit のマウント時に onChange を呼び出して更新することになります
仕方ないのですがそれはなんか気持ち悪さがあります

親で state 管理しないものなら 初期値を渡すだけで修正した値は Edit の中で持っておいて 親が値を使いたいときに Edit から取り出します
これだと自然なのですよね

Edit コンポーネントのモジュールから関数もエクスポートすれば ロジックは Edit モジュールの中で持てます
しかし Edit を使うのに 初期値を作る部分とコンポーネント部分で 2 つの処理が必要になるのが面倒です
例えば API で選択肢を取得して初期値が null なら最初の選択肢を初期値にする場合 初期値のために関数で API を呼び出して コンポーネント内でも選択肢を作るために API を呼び出す必要があるので 関数とコンポーネントの両方で API を呼び出すことになります
それを避けるなら関数は初期値の他に選択肢も返して それもコンポーネントに渡すという作りになりますが やることが増えます
やりたいのは単純に Edit コンポーネントを使って props を渡すだけにしたいのですけど

onChange の場合でも困るところはあります
変更イベントを beforeunload などと関連付けていれば ユーザーは何も編集してないのに変更ありとして扱われます
初期化が null の場合に値を入れたり 不正文字を除去など繰り返し行っても問題ないものならいいですが そうでない場合は判断するのが難しいです
入力値を制御するライブラリでは onChange を即呼び出すものを見かけますが 組み合わせるライブラリの相性とかもあるのか ときどきうまく動いてなかったりするのですよね
レンダリング中に同期的に呼び出すと問題ありそうですし useEffect 通しても その他の useEffect との順序が影響しそうです
.NET Framework と .NET を混ぜて使う
.NET Framework で作られたレガシーなアプリがあって サポート期間とか色々な事情で .NET には移行しない
そのアプリの一部機能を使う別アプリを新規に作るけど 最新 LTS の .NET 6.0 を使いたい
そんなことできるのかなと思って試してみたら普通にできた

ソリューションの中に新規プロジェクトを作るとき .NET のプロジェクトを選ぶ
作ったプロジェクトの依存関係の設定でソリューション内から .NET Framework のアプリを選ぶ

あとは .NET Framework 側のメソッドを単純に呼び出すだけ

WindowsFormsApp1.Class1.something()

これで動いた

ただし WinForms のアプリの Form を開く機能はコンソールアプリからは呼び出せない
コンパイル時にエラーは出ないけど実行時にアセンブリが見つからないってエラーが出る
.NET Framework 側のプロジェクトのビルド時に依存アセンブリは考慮されてそうだけど 見つからないらしい

.NET 側もアプリの種類を WinForms にすれば問題なく開ける
.NET アプリから .NET Framework 経由で Form を開くと .NET Framework アプリでも WinForms のアセンブリは .NET 側の SDK のものが使われてるのかな?

コンソールアプリとしてプロジェクトを作ってしまった場合はプロジェクトのプロパティを開いて 「アプリケーション > 全般」 の部分で以下のように設定すれば使えるようになる

出力の種類 → Windows アプリケーション
ターゲット OS → Windows
Windows フォーム → チェック入れる

WPF なら Windows Presentation Foundation の方にチェック
VSCode で WSL 内のファイルを編集する
VSCode の拡張機能で WSL と接続できます
接続すると そのウィンドウは WSL 用に開き直されますが まだフォルダを開いた状態にはなっていません
フォルダを開いたら あとは Windows のときと同じようにサイドバーからファイルを選んで編集できます

特定のフォルダを開かずに WSL 内のファイルを編集したいときはフォルダを開かずそのまま使えます
Ctrl-O や File > Open File でファイルを開こうとすると Windows のダイアログのかわりにコマンドメニューが表示されます
ここでパスを指定することでファイルを開けます

ですが あまりこの方法は使いやすくないです
WSL なのでコマンドラインから操作したいです

そういうときは Ctrl-@ でターミナルを開きます
WSL に接続してると PowerShell の代わりに WSL のシェルが起動します
ここで

code foo.txt

のように code コマンドを実行すると VSCode のタブで開いてくれます
ファイルがなければ新規作成されます
nano や micro など WSL 内のエディタを開く感じで VSCode でファイルを編集できます

なんらかのコマンドの出力結果を VSCode で編集したり確認したりしたいなら code コマンドのパラメータに 「-」 を指定することで標準入力を受け取れます

apt list --installed | code -

のようにできます

かなり便利なので Windows Terminal で WSL は開かずに VSCode だけで十分かもしれません
Firefox を CDP で操作する
Chrome と同じ感じで接続

リモートデバッギングを有効にして起動

firefox --remote-debugging-port 9222

接続とページ遷移は Chrome と同じ感じでできる

import CDP from "chrome-remote-interface"

const cdp = await CDP()
await cdp.Page.navigate({ url: "https://github.com/" })

ページ内でスクリプトの実行は Chrome だと↓で動く

const expression = `document.title`
await cdp.Runtime.evaluate({ expression, returnByValue: true })

でも Firefox だと context が null と言われてエラー
Chrome のドキュメントだとオプショナルだけど evaluate のパラメーターに contextId を渡せる
ExecutionContextId という型で実体は int
試しに 0 や 1 など渡してみても指定の id の context がみつからないというエラー

context を作る方法を探すと Page.createIsolatedWorld で isolateworld を作ると返り値として ExecutionContextId が受け取れるみたい
Page.createIsolatedWorld には frameId が必要になるけどこれは Page.navigate で受け取れる
試してみたけどフレームが見つからないと言われてエラー

やっぱり Firefox を直接 CDP で動かすのはやめたほうが良さそう

調べてると Selenium は Firefox の CDP サポートをやめる予定があるみたい
https://github.com/SeleniumHQ/selenium/issues/11736

理由として Firefox の CDP 対応が不完全で新しい BiDi の対応を重視してるみたい
https://w3c.github.io/webdriver-bidi/

BiDi が標準化されて普及するなら Playwright もこっちに切り替えていく方針なのかなと思って調べるとこんな QA が出てきた
https://github.com/microsoft/playwright/discussions/14014
動画内での発言で 全メジャーブラウザがサポートされない限り BiDi の実装予定はないみたい
サポートされれば検討するとか
現状では積極的に変えていくつもりはなく様子見みたい
Iterator helpers が使えなくなった
Chrome 117 でリリースされた新機能の Iterator helpers ですが 早速ウェブ互換の問題が起きたとかで削除されました

https://github.com/tc39/proposal-iterator-helpers/issues/286
https://bugs.chromium.org/p/chromium/issues/detail?id=1480783

すでに Chrome の最新版では動かなくなっています
Edge ではまだ動きますが 近いうちに削除されると思います

配列のグループ化のときもでしたが またかと言う感じですね
将来的に機能が追加されるなんてわかってるはずなので それを考慮してないようなサイトは相手しなくていいと思うんです
というか ウェブ互換をずっと気にしてると毎回こういう事が起こります
本当 そろそろ互換性無視で新機能追加していったり破壊的変更をしてもいいと思うんです

最低限 「組み込みの prototype には触れるな」 みたいな 将来の機能追加で影響を受けそうな部分に関する◯◯してはいけないというルールを定めて それを無視してもいいけど無視した結果壊れても 対応しないくらいなことはしたほうがいいと思います

配列のグループ化は結局期待してたのとは別の API になるということで解決になりましたが Iterator helpers は使い方変えないでもらいたいですね

今月の TC39 のミーティングの議題に上がっているので そこで方針を決めるのかもですね
https://github.com/tc39/agendas/blob/main/2023/09.md
Chrome 117 で JSON を開いたときにフォーマット表示する機能が増えてた
新機能一覧に載ってなかったので気づいてませんでしたが Chrome で JSON ファイルを直接開いたときにヘッダーが表示されるようなっていました
ヘッダーのメニューには 「プリティ プリント」 のチェックボックスがあります

これにチェックを入れると JSON がきれいにフォーマットされて読みやすくなります

以前はこんなのなかった気がすると思って Chrome 116 で開いてみるとありませんでした
Chrome 117 の新機能のようです
これまでは JSON のフォーマットのために VSCode に貼り付けたり devtools のレスポンスで表示したりしていたので この機能があると便利になりますね

ちなみに Edge は 117 でもこの機能はありません
というか Edge ではデフォルトできれいにフォーマットされて色付けもされています
生のレスポンスを見たいときに Ctrl-U でソースコードを表示したり devtools のレスポンスで確認しないといけないです
これはこれで少し不便だったりもします

ちなみに JSON しか確認していませんが他のファイル形式でもフォーマット表示してくれるのかもしれません
Fastify のセッション
久々に Fastify を使ったらセッションってどのプラグイン使えばいいのだっけとなったので
https://fastify.dev/ecosystem

公式のプラグインだと 3 種類

@fastify/cookie
@fastify/session
@fastify/secure-session

@fastify/cookie はセッションというよりは cookie を扱うライブラリ
だけど署名機能があるので koa の koa-session 相当のものならこれで十分
ただし あくまで cookie ライブラリなのでセッション風に特定のオブジェクトを更新するだけで後は自動でやってくれるということはない
cookie を読み取って署名チェックや cookie をレスポンスで送信するなどの制御は自分で実装する必要あり
それらを行うための関数は用意されるので addHook を使って onRequest や onSend にフックを追加すれば良い

@fastify/session はサーバーサイドのセッション
PHP みたいなもの
ID を cookie に書き込んでデータはサーバー側で持つ
デフォルトだとセッションデータはメモリ上に保持するのでセッション数が増えるとメモリを使うしサーバーのリスタートで消える
ストアの実装をカスタマイズできるのでちゃんとしたところで使うならファイル等に書き込んだほうがいい
redis に保存するなら一応コミュニティに別のプラグインがある
ただ スターがほとんどなくてマイナーみたいなのでストアを自作でもいいかも
このプラグインを使うのに @fastify/cookie が必須
内部で自動でやってくれないので自分でインストールと register しないといけない

@fastify/secure-session はクライアントサイドでデータを持つセッション
@fastify/cookie の署名とは違って暗号化してくれるのでユーザーが中身を見れない
hapi の iron 的なもの
暗号化には sodium-native を使ってる
sodium でググってると高速な暗号化というのを見かけたけど Node.js 組み込みの crypto と比べてどっちが速いのかはわからない
わざわざ外部のものを使ってるんだから組み込みよりは高速?
事前に付属ツールで鍵を発行しておいて プラグインの登録時にその鍵を渡す必要あり
鍵を使わずに secret にパスワード指定でも動かせるけど 起動時に毎回内部で鍵を生成してるので少し遅くなるらしい
内部で @fastify/cookie を使ってるけど @fastify/session とは違ってインストールも register も自動でやってくれるので意識しなくて良い
React 18 で unmount 後に state を更新したときの警告がなくなってた
未だに React 18 より 16 や 17 を使ってることが多いです
そんななので今更気づいたのですが 18 では コンポーネントのアンマウント後に state を更新したときに出ていた警告がなくなっていました

こういうの

Warning: Can't perform a React state update on an unmounted component.
This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

表示させる例

export default () => {
const [shown, setShown] = useState(false)
return (
<div>
<button onClick={() => setShown(!shown)}>toggle</button>
{shown && <Component/>}
</div>
)
}

const Component = () => {
const [count, setCount] = useState(0)
const onClick = () => {
setTimeout(() => {
setCount(count => count + 1)
}, 3000)
}
return (
<div>
<button onClick={onClick}>{count}</button>
</div>
)
}

toggle ボタンのクリックで Component の有無を切り替えます
Component はボタンをクリックするとカウントアップするコンポーネントですが 3 秒ディレイしてからカウントアップします
この 3 秒の間に Component を表示しないようにすると アンマウントされて その後に state の更新が起きるので警告が出ます

実際のケースでは fetch など非同期処理を行うコンポーネントで その処理が完了する前に別のページに遷移したりタブを切り替えたりすることで発生することが多いです

これの対処をちゃんとやると面倒です
アンマウント済みかを示すフラグを用意してアンマウント時に更新します
state 更新時にはフラグを見てアンマウント済みなら更新をスキップします
面倒な上にコードも複雑化する嫌なやつです

実際こういう一回限りの setState がアンマウント後に行われてもメモリリークにはならないです
それでも警告として出る以上対処しようとして その結果 面倒が多く複雑になるという問題があったのでなくしたのかもですね

メモリリークになるのは setInterval や外部のサブスクリプションなどで 1 回限りではなくイベントが起きるたびに更新が発生するものです
こういうのです

useEffect(() => {
setInterval(() => {
setState(Date.now())
}, 1000)
}, [])

この警告は出ていても無視していいケースが多かったですが 無くしてしまうとこういうケースに気づけないという問題はありそうです
localhost へのアクセスは preflight リクエストが発生する
localhost へのアクセスで単純な fetch なのに preflight リクエストが発生しました
追加ヘッダーもなく GET リクエストで

fetch(url)

だけなのですけど

各ページで devtools を開いて コンソールから fetch を実行し ネットワークパネルで preflight リクエストの有無を確認します
リクエスト先は 「http://localhost:8000」 です

「https://let.blog.jp/」 → あり
「https://www.yahoo.co.jp/」 → あり
「https://www.google.com/」 → あり

「http://var.blog.jp/」 → なし
「http://localhost:7000」 → なし

外部からだからというわけではなく https のページから localhost へのアクセスだと発生するようです
localhost 以外からでも http のページからだと発生しません

localhost 関係なく https → http なら発生するのかと思って 試してみましたが発生しませんでした
https から localhost だけのようです

localhost の代わりに 127.0.0.1 としても同様ですが 192.168.1.11 など自身の IP アドレス指定にした場合は発生しません

関係ないですが Github や MDN のページから fetch を実行すると CSP でブロックされました
これがあるから CSP は嫌なんですよね
devtools や拡張機能からなら無視してほしいものです
大幅なリファクタリングだとテストがあまり役立たない
なにかを作ったときってだいたい画面で動作確認したりしてるので ちゃんと動いてるかの確認という意味ではあまりテストが必要と思ったことはないです
ときどきかなり複雑なロジックなものがあって 色々なケースを試すときに手作業よりはテストツールでやったほうが楽かなと思うくらいです
なので テストの目的は仕様を記載するか あれこれ変更したときに元の動作が維持できているかの確認という意図が強めです
一度作ったらその部分のコードにはできるだけ触れないという人もいますが 個人的には気になるところがあれば頻繁に修正加えていくタイプなのでリファクタリング時が一番の目的かもしれません

なのですが 大きく書き換えるとリファクタリング時に動作が変わっていないかのテストに使えないことが多いのですよね
小さい規模だと使えることが多いですが 期待するのは大きい規模での変更です
なのにそういうときにあまり使えないとなると 丁寧にテストしてもあまり意味ないかなぁという気持ちになりました

例えばモジュールまるごと置き換えるような場合
A モジュールがあってそれを使う B モジュールがあります

A はこういう感じです

export const logic1 = () => {}
export const logic2 = () => {}
export const logic3 = () => {}
// ...

export default () => {
// ここで logic1 や logic2 などを使う
}

B では基本 default export されたものを使います
場合によっては直接 logic1 などを使うかもしれませんが基本は default export のものです

複雑なロジックをテストするときって基本まとまった部分じゃなくて小さい単位で詳細にテストします
上の例だと logic1 ~ logic3 などです
default export する関数だと中でこれらを複数使ってるので この関数を使って logic1 の動きや logic2 の動きまで詳細にテストするのは大変です
例えば logic3 が重たい処理だった場合に logic1 部分のテストだけでも時間がかかってしまいますし

なので default export の関数自体のテストはシンプルで 中で呼び出す logic1 などに渡す引数が間違ってないかを確認する程度の目的です
この関数自体が十分にシンプルなら省略することもあります

リファクタリングで logic1 の中身だけ修正しようとなった場合は logic1 はちゃんとテストされているので 効果が高いです
しかし 大きな規模だと A モジュールをまるごと作り直すということもありえます
そうなると logic1 や logic2 という関数の分け方もなくなります
過去のテストは使い回せないです
B に影響させない範囲なら default export の関数のインターフェースはそのままですが この関数のテストは簡単なものしかありません
このテストが通っても最低限のパターンでしかなくて 複雑なケースが動くことは保証できません

これに対応しようとすると logic1 ~ logic3 の分のテストを default export の関数でもテストしておく必要が出てきます
それはテストケースがかなり増えて大変ですし 関数が何重にもなってくると現実的ではないです
B モジュールを使う C モジュールがあれば C モジュールでも A モジュールの中身までテストするということになります
C モジュールを使う D モジュール……と続いて Z モジュールまで行ったとき Z モジュールのテストで A モジュール内の logic1 の分岐全部をテストなんてやってられないですよね

そう考えるとリファクタリング時の安全を求めるという目的でのテストはあまり効率的ではなさそうです
tmux で画面分割して操作したい
Docker のコンテナで作業中にもう一つターミナルが欲しくなるときが時々あります
もうひとつウィンドウを起動して コンテナ ID を調べて docker exec するのも少し面倒なので久々に tmux を使いましたが全然使い方がわかりません
ググっても必要以上の情報がありすぎなんですよね
ということで最低限の分割して切り替えて使うだけの方法

まずは tmux コマンドで起動します
tmux 起動中にプレフィックスキー (Ctrl-B) を押した後になにかのキーを押すことで tmux を操作できます

" → 上下に分割
% → 左右に分割
o → 分割したペインのフォーカス切り替え
z → 分割したペインの最大化切り替え
{ → 分割したペインの並び変更(前と交換)
} → 分割したペインの並び変更(次と交換)

不便な点として tmux を使うと過去のログも tmux 内で管理されてしまい ターミナル上のマウススクロール機能で戻れないです
プレフィックスキーと [ キーで過去ログモードに入れます
エディタのようにカーソルを動かせます
Esc キーでキャンセルできます

一応マウスに対応させる設定もあるようですけど Linux や Mac の標準ターミナル向けみたいですし Windows でしかも WSL 内の Docker 内の tmux となると面倒ごとが多そうです
しかも 普段使いの環境ではなく 使い捨て環境に tmux を入れる前提なので tmux の設定ファイルを書き換えるみたいなのは向いてないのでパスです
孫プロセスをバックグラウンドで実行するときにプロセスが残る
こういう JavaScript ファイルと ShellScript ファイルがあります

[job.sh]
#!/bin/bash

echo pre something something

./job.js &

echo post something something

[job.js]
#!/usr/bin/env node

console.log("Start job.js")

setTimeout(() => {
console.log("initialized")
}, 500)

// keep process
setInterval(() => {}, 100000)

job.js は常駐するプロセスです
ここでは setInterval でプロセスが終了しないようにしています
これを job.sh から起動します
job.sh は別の Node.js プロセスから起動します
job.sh を起動する側はこんな感じです

const cp = require("child_process")

const sub = cp.spawn("./job.sh")

sub.stdout.setEncoding("utf8")
sub.stdout.on("data", console.log)
sub.on("close", () => {
console.log("CLOSED")
})

job.sh や job.js の出力を受け取りたいので stdout の標準出力にリスナをつけています
job.js は常駐しますがすべてを受け取る必要はなくて 起動直後の内容だけでいいです
つまりは job.sh が終われば close イベントが起きてほしいです
しかし close イベントは起きません
子プロセスである job.sh は終了済みなのですが孫プロセスの job.js が生きていることで stdout や stderr が生きてるのでこれらが閉じられるまでは Node.js は子プロセスが終了したとみなしてくれないようです
放置でもいい気はしますがずっと残るわけなのでメモリリーク状態です

stdio が問題なので ignore にしてしまえば標準入出力を使わないようにできて これなら即終了とみなされ CLOSED が表示されます

const sub = cp.spawn("./job.sh", { stdio: "ignore" })

ただし問題があって標準出力を受け取れないです
ファイルに出力するようにして ファイルを読み取るということはできますが 回りくどくてイマイチです

起動する側もサーバーみたいな常駐するものだとメモリリークになるのを気にしないとですけど 一回限りのスクリプトでスクリプトが終了しないのが嫌という場合は unref で解決できます

const cp = require("child_process")

sub = cp.spawn("./job.sh")
sub.stdout.setEncoding("utf8")
sub.stdout.on("data", console.log)
sub.on("close", () => {
console.log("CLOSED")
})

setTimeout(() => {
sub.unref()
sub.stdout.unref()
sub.stderr.unref()
}, 1000)

必要な出力が出る程度に 1 秒待ってから unref しています
ちゃんとやるなら stdout の出力から必要なものを受け取れたら実行みたいにしたほうがいいです

まぁ終了させるなら unref していかなくても process.exit でもいいのですけどね

考えてみると常駐してるものから出力を受け取り続ける以上終了しないのが正常ですよね

job.sh で job.js を起動する部分で

./job.js > file 2>&1 &

みたいにしてしまったほうがいいかもしれませんね
やっぱり日記化してる
Short の方は短くシンプルに要点だけにしようとか思っていたはず
技術ブログ寄りな感じ
だけど振り返ると メインのブログの方の分量が少ない版みたいな状況になってます

意識しないと日記状態になるんですよね
時系列順にやったことをだらだらと書いてる感じ
理想形は 問題点や記事でやることの概要と記事全体の結論を最初に書いてから その詳細の説明や調べてる間にわかったところをまとめて書く
やってはみたけどムダだったあれこれは含めない
たぶんそんな感じ

直前の記事を書き直すならこんな感じ



VSCode のデバッグ実行時に pino からのログ出力が表示されません
原因は pino の出力方法が process.stdout.write を使うからでした
VSCode のデバッグ実行時 デフォルトでは標準出力はキャプチャされません

標準出力のキャプチャが必要な場合は launch.json を作って 「"outputCapture": "std"」 を追加する必要があります
追加する場所は configurations の各オブジェクトのトップレベルです

以下が確認用コードです
ターミナルで実行すると 3 つのログが出力されますが VSCode でデバッグ実行すると最後の CONSOLE LOG しか出ないはずです
outputCapture を設定後には 3 つとも出力されるようになります

const pino = require("pino")

const logger = pino({ level: "info" })

logger.info("PINO LOG")
process.stdout.write("STDOUT LOG\n")
console.log("CONSOLE LOG")



これくらいで良いはず なんですよね
感情が入らず無機質に
この分量ならコード部分を含めなければ続きを読むボタン押さなくても全体が読めますし

でもまぁ書き始める段階で書く内容が確定してないというのも原因としてあります
上の記事なんて書く時点では 「中で pino が使われてると VSCode でログが出ない」 くらいなものでした
記事に書いてる途中で あれはどうだろう そういえばこのパターンは試してなかったとか 色々思いついて書きながら追加であれこれやっていて 書き終わるまでに解決してるというケースはけっこうあります
そんななので自然と時系列でやったことが順に書かれていく傾向があります

そんなことをしてると理想どおりにするには書き終わってからまとめ直すしかないのですが 一旦書いたら せっかく書いたのにもったいない感が出てくるのと面倒だしこれでいいかとなってきます
やっぱり私はちゃんとした文章を書くのは苦手ですね
思いついたことを適当に書いてるのがちょうどいいです
VSCode のデバッグ実行で pino のログが出ない
内部で pino が使われているものを使っていたとき ログが表示されるはずなのに出ていません
console.log を使っている出力は表示されています
VSCode でデバッグ実行していたので 一応ターミナルから直接実行もしてみると ちゃんと表示できています
なぜ?

pino 側の問題かなと思って直接 pino を使って簡単なコードを用意しました

const pino = require("pino")

const logger = pino({ level: "info" })

logger.info("PINO LOG")
console.log("CONSOLE LOG")

これをデバッグ実行すると これでも CONSOLE LOG だけしか表示されないです
中でどういう出力をしてるのだろうと pino の中を見ると stream への書き込みを行っていました
stream を作成してるのはここです
https://github.com/pinojs/pino/blob/v8.15.1/lib/tools.js#L329

stream = buildSafeSonicBoom({ fd: process.stdout.fd || 1 })

SonicBoom に { fd: 1 } を渡しています
ターミナルからでも VSCode のデバッグ実行からでも process.stdout.fd は 1 でした
ということは 普通に process.stdout.write しても出なさそうですね

process.stdout.write("STDOUT LOG\n")
console.log("CONSOLE LOG")

を試してみましたが やはり CONSOLE LOG だけでした

VSCode のデバッグ実行だと console.log が置き換えられてそうです
となると process.stdout.write を置き換えて 中で console.log するしかない?
でもデバッグ実行のためだけにやりたくない変更です
それに stdout への直接書き込みは末尾に改行が自動追加されないですが console.log だと自動追加されて消せなかったはずですし

デバッグ実行してる場合の仕方ないものとして諦めつつも一応ググってみると解決策がありました
launch.json を作って設定に 「"outputCapture": "std"」 を追加すれば標準出力もキャプチャしてくれるようです

{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
// 略
"outputCapture": "std"
}
]
}

これで pino のログも表示されました
max-age が効かない
キャッシュ設定を変更して動作確認していたら max-age を設定しているのに毎回サーバーに問い合わせが発生して困っていました
devtools の Network タブを見たときに (disk cache) や (memory cache) となっていてほしいのですがなってくれません
リクエストが発生して 304 が返ってきています
そのレスポンスのヘッダーを見るとちゃんと max-age が付いているのですけどリロードするとまたリクエストが発生します

色々試したところ max-age でキャッシュからロードしてくれるのはリソース扱いのときだけのようです
ブラウザで直接 HTML ファイルや JavaScript ファイルを開いた場合 これらのファイルはキャッシュを見ずにリクエストが発生するようです
HTML から script タグで JavaScript をロードしたり fetch で HTML ファイルを取得するようなケースではキャッシュが使われています

これのせいで無駄に時間を使うことになりました
前からこんな動きでしたっけ
というかこれは共通の仕様? Chrome の独自仕様?
MDN を軽く見た感じではアクセスするコンテキストで動作の違いとかはなさそうでした

◯ 確認用

require("http").createServer((req, res) => {
if (req.url === "/") {
res.writeHead(200, {
"Content-type": "text/html",
"Cache-Control": "max-age=3600",
})
res.end(`<script src="/a.js"></script><h1>HTML</h1>`)
return
}
if (req.url === "/a.js") {
res.writeHead(200, {
"Content-type": "text/javascript",
"Cache-Control": "max-age=3600",
})
res.end(`console.log(1)`)
return
}
res.writeHead(404)
res.end(`NOT FOUND`)
}).listen(8000)

「http://localhost:8000」 にアクセスして devtools を開いてリロードします
a.js のほうだけキャッシュが使われてるはずです
「fetch("/")」で / にアクセスすると HTML ファイルもキャッシュが使われます

こういう動きだと HTML もキャッシュさせたい場合は E-Tag や LastModified を使って 304 を返せるようにしておいたほうが良さそうですね

SPA を作るときは HTML ページだけはエントリポイントとして更新するために max-age 付けたらダメなので例外にする工夫が必要だったのですが それがいらないという点では便利ですね



リロードで確認すると max-age が無視されるみたいです
https://blog.jxck.io/entries/2023-11-05/reload-and-cache.html

リンクを用意して移動してきた場合はページを開くリクエストでもキャッシュが使われてました
ページを開くリクエストでキャッシュが無効化されるなら SPA のエントリポイントなどの HTML もまとめて max-age をつけておいても大丈夫かもと思ったのに そうはいかなそうです
HTML にも max-age をつけると外部から移動してきたときだけキャッシュが使われて最新版にならない問題が起きてしまいます
hr で水平線が表示されない
hr タグを書いているのに表示されていないところがありました
他のところは表示されています
devtools の Elements タブで見ても hr タグには特別なスタイルは当たっていないようです

原因は親要素が display: flex かつ縦並びになっていたことでした

<div style="
display: flex;
flex-direction: column;
">
<p>a</p>
<hr>
<p>b</p>
</div>

こういう HTML で再現できます

hr に width: 100% を指定することで hr を表示できます

ですが align-items のデフォルトは stretch なので width: 100% を指定しなくても横幅いっぱいになるはずです
実際の値を見てみても stretch になっていました
なぜ width 指定なしでうまく表示されないのでしょうか

もう少しあれこれ見てみると原因はユーザーエージェントのデフォルトスタイルシートでした
Chrome 系ブラウザでは hr のマージン関係のデフォルトがこうなっています

margin-block-start: 0.5em;
margin-block-end: 0.5em;
margin-inline-start: auto;
margin-inline-end: auto;

margin-inline が左右なのでこれが auto ということは中身のサイズに合わせて左右に自動でマージンが付きます
hr は中身が無いので幅が 0 になって表示されてないということでした

デフォルトは auto じゃなくて 0 でいいと思うのですけど
VSCode で最初に開くときに以前のウィンドウを復元したくない
VSCode の全ウィンドウを閉じた状態で VSCode を起動すると最後に開いていた全部のウィンドウが起動します
「File > Exit」でまとめて終了すると全部が起動します

それぞれのウィンドウが結構な量のメモリを消費するので それらのワークスペースを開かない限りは復元せずに何もない空の状態のウィンドウが起動してほしいです

設定を探すと window.restoreWindows というのがありました
none にすると良いようです

"window.restoreWindows": "none"

これで解決かと思ったのですが 複数のウィンドウが開くときがあります
フォルダを開いておらず未保存のファイルが残っているとそのウィンドウは必ず自動で復元されるようです

フォルダを開いていない場合は ウィンドウを復元しなければ未保存のファイルにアクセスする方法が残ってないからだと思います
フォルダを開いていないウィンドウはワークスペースとして管理して ワークスペースを開くから一覧出してくれるとかして くれるといいのですけどね
そうすれば一覧からいつでも開けるので 未保存があっても復元せずに済みますし
IronPython3 使ってみた
Python で .NET 機能が使えるというものです
https://github.com/IronLanguages/ironpython3

以前こんな記事を書きました
当時はまだ Python2.7 互換しかありませんでした
さすがに 3 じゃないのは嫌かなと使わなかったのですが 今年 7 月に 3.4 が出ました
本家 Python は 3.11 が Stable なので結構古いのですが それでも 3 系なのは嬉しいところです

とりあえずどんな感じで使えるのか試してみようと思います
ドキュメントにインストール方法があったのでこの通りに進めます
https://github.com/IronLanguages/ironpython3/blob/master/Documentation/installing.md

dotnet コマンドのツールとしてスタンドアロンインタプリタが使えるようです

dotnet tool install --global ironpython.console

グローバルに入れたので ipy コマンドが使えるようになりました
これが普通の python3 や py コマンド相当のもののようです

単純に ipy だけで実行すると REPL が使えます

C:\Users\WDAGUtilityAccount>ipy
IronPython 3.4.1 (3.4.1.1000)
[.NETCoreApp,Version=v6.0 on .NET 6.0.21 (64-bit)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

引数に py ファイルを渡すとそのファイルを実行できます

ほぼ普通の Python と同じみたいですね
ライブラリのフォルダは

C:\Users\<USER>\.dotnet\tools\.store\ironpython.console\3.4.1\ironpython.console\3.4.1\tools\net6.0\any\lib

ここに http とか os.py とか glob.py などのパッケージが配置されています
3.4.1 や net6.0 の部分はバージョンで変わるはずです

.NET 機能に触れてみます

C:\Users\WDAGUtilityAccount>ipy
IronPython 3.4.1 (3.4.1.1000)
[.NETCoreApp,Version=v6.0 on .NET 6.0.21 (64-bit)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import System
>>> System
<module 'System' (CLS module from System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)>
>>> System.Console
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'System' object has no attribute 'Console'
>>> import clr
>>> clr.AddReference("System.Console")
>>> System.Console
<class 'Console'>
>>> System.Console.WriteLine("a")
a
>>> System.Console.WriteLine("{0} + {1} = {2}", 10, 20, 30)
10 + 20 = 30

.NET の System は 「import System」 でインポートできます
デフォルトで System.Runtime.dll のアセンブリがロードされてるようで System.Array とか System.Activator とかが使えます
System.Console は System.Console.dll なので System.Console にアクセスしても見つかりません
clr.AddReference で参照に追加することで使えるようになります

ただ Python は Python のままでも十分高機能なのでコンソールだとあまり .NET 機能を使える嬉しさがないです
やっぱり GUI を使えてこそだと思うので GUI を試してみようと思います
Readme では WinForms でダイアログを出す例があるのでこれを試してみます

import clr
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import MessageBox, MessageBoxButtons

MessageBox.Show("Hello World!", "Greetings", MessageBoxButtons.OKCancel)

OSError: [Errno -2146232800] Could not add reference to assembly System.Windows.Forms

アセンブリの読み込みに失敗するようです
WinForms のアセンブリはライブラリに含まれていないのでしょうか
そういえばインストール時に指定した名前は ironpyton.console です
ターゲットフレームワークが console になってるのもかもしれません
スタンドアロンのインストールですし コマンドライン専用ツールの可能性もあります
一応 SDK には dll があるので動的なロードでフルパスで指定してみましたがそれでもエラーでした
このツールは OS も問わないものみたいですし Windows 固有の WinForms などは対応してないのかもですね

インストール方法には .NET アプリに埋め込むタイプもあるようですし WinForms や WPF アプリに IronPython を埋め込めば GUI も使えるのかもです
脱 TypeScript の話題
Turbo8 が脱 TypeScript と話題になっていました
そもそも Turbo が何かすら知らないのですが話題になるくらいなら有名なものなのでしょうか

探したところこれっぽいです
https://turbo.hotwired.dev/

今が 7.3 なので次が 8 です
リポジトリを見ると TypeScript を JavaScript に書き換えるコミットが行われていましたし間違いなさそうです

初めて見るものなので軽くどんなものか見てみると JavaScript を書く量を減らしてくれるそうです
色々な便利機能が詰まっているライブラリということでしょうか

サンプルでは turbo-frame とか turbo-stream とかの HTML タグが使われていました
CustomElements を使うライブラリのようですね
ソースコードを見ても CustomElements を定義しています
https://github.com/hotwired/turbo/blob/v7.3.0/src/elements/index.ts

なんとなくどういう系のものかはわかりましたが マイナーなものに思います
TypeScript に反対の人ってそこそこいて Github の issue とか見てるとときどき議論になってたりします
珍しいものではないと思うのですがなぜマイナーライブラリで TypeScript やめただけでそんな話題になったのでしょうか

話題になってる分 コメントも多かったのでそこを見てると 記事を書いた DHH という人は RoR を作った人らしいです
RoR を調べて作者を見てみると確かに名前が一致していました
RoR 作者なら話題になるのも納得ですね

個人的には同意見の人がいて嬉しいものです
最近は流行ってるからと何も考えずとりあえず TypeScript という人が増えてるので本当に必要か考え直すきっかけになるといいですね

とはいえ ライブラリという点では TypeScript 使ってくれてる方が良い点が多いのは確かです
使う側でライブラリ内のプロパティの補完候補が出たり 引数の情報が見れたりします
これは JavaScript を書く場合でも使えるので ライブラリが TypeScript で末端のアプリは JavaScript というのが快適です
型情報でコードが読みにくくなったり コンパイラの都合で無駄な時間を取られたくないので自分が書くのは JavaScript にしておきたいです
また ライブラリが TypeScript というだけなら直接 TypeScript を使う場合と違ってほとんど VSCode が重たくなりません

ただ必要なのは公開される関数の入出力の情報なので ライブラリ側も .d.ts ファイルを別に用意してくれていればライブラリも JavaScript でもいいと思います

引数の情報がわかる利点については 常に良いとは言えないです
シンプルな型ならいいのですが ヒドイものだと何重にもなったジェネリクスが複数あるような型になっていて VSCode 上のポップアップで型定義が 5 行以上だったりします
そんな複雑な型情報見せられても意味不明だしなんの参考にもならないです
string とか number[] みたいにスッキリしてればいいのですがそうでないなら価値はほぼないです

TypeScript の型って悪い意味で自由すぎると思うのですよね
1 から N までの整数のみ許可する型を作る みたいなことをやってるひともいますが 中身は複雑すぎて TypeScript 使ってても理解できる人のほうが少ないんじゃないかというようなものもあります
JavaScript が自由すぎてつらいから TypeScript と言ってる人がいますが 同じことを TypeScript の型でやってるだけだと思います
ベースが動的な言語な以上 無理やり合わせても仕方ないので PHP8.0 くらいのジェネリクスもないようなシンプル型くらいで良かったと思うんです
CSS の position:sticky で固定されたときだけスタイルを当てれるようになる
Chrome の現バージョン 116 で DevTrial です
https://chromestatus.com/feature/5072263730167808

詳しい説明
https://lilles.github.io/explainers/state_container_queries.html

position: sticky でスクロールしたときに要素を簡単に固定できるようになりましたが 固定されてるときだけスタイルを変えたいということはよくありました
それができるようになります

使い方はコンテナクエリを使って

@container state(stuck: top) {
#sticky-child { font-size: 75% }
}

のようになるそうです

HTML の例だと

<style>
#sticky {
container-name: my-menu;
container-type: sticky;
position: sticky;
top: 0px;
height: 100px;
}

#sticky-child {
background-color: orange;
color: white;
height: 100%;
}

@container my-menu state(stuck: top) {
#sticky-child { width: 50%; }
}
</style>
<div id="sticky">
<div id="sticky-child">
Sticky
</div>
</div>

できるようになるのは嬉しいのですが 少し手間なのが難点ですね
コンテナクエリが必須ですし contaner-type の指定も必要です

お手軽に擬似クラスで :stuck でいいと思うのですが パフォーマンスの懸念など色々あってコンテナクエリになったようです
CSS に相対カラーの構文が追加されるみたい
CSS Relative Color Syntax (RCS) というのが Chrome 118 で DevTrial のようです
https://chromestatus.com/feature/5205844613922816
https://www.w3.org/TR/css-color-5/#relative-colors

こういう感じです

div {
background: rgb(from var(--bg-color) r g b / 80%);
}

rgb や hsl などの色空間の関数に from で元になる色を指定してから 次に各値を指定します
構文的には

rgb(from 元の色 R G B / 透過率)

rgb 関数なので R と G と B を指定します
透過率は省略可です

R と G と B には これまでの rgb 関数のように 0~255 の数値や%で指定できます
相対と言いつつもこの%は 100% が 255 に相当するもので 元の色に対する割合ではありません

rgb(from red 100% 100% 100%)

と書けば rgb(255, 255, 255) = #ffffff と同じです
red は意味のないものになります

from の色を使うには 数値と%以外の特殊なもので r と g と b を使います
これを使うと元の色の R と G と B の値になります

rgb(from red r g b)

と書くと元の色そのままです

rgb(from red r r r)

と書くと G と B も R の値 (255) になるので rgb(255, 255, 255) です
元の色を使って計算するときは calc を使います

rgb(from rgb(100,100,100) calc(r * 1.1) calc(g * 1.5) calc(b * 2))

これの結果は rgb(110, 150, 200) になります
足し算で直接数値を足したい場合は小数値で扱うことになります
1 が 255 に相当します

rgb(from rgb(100,100,100) calc(r + 0.5) calc(g + 0.1) calc(b + 1))

これの結果は rgb(228, 126, 255) になります
0.5 は 128 なので 100 + 128 = 228 です
1 を足すと 255 を超えてしまうので 255 になります

rgb で使うよりも hsl で hue だけを変えたいみたいなケースのほうが使うかもですね
Chrome 118 で HTML の search 要素に対応するみたい
https://chromestatus.com/feature/5126108151808000

以前話題になっていた HTML の search タグですが Chrome 118 から対応するみたいです

機能としては特になくアクセシビリティのためのものらしいです
「<div role=search>」 と書くのと同じらしいです

検索ボックスが表示されたりはしないので アクセシビリティ系を気にしない人にとっては 無視していいタグです
main とか aside とか header とか nav とか こういう系統のタグです
コンストラクタを見ても main などと同じで HTMLElement になっています

document.createElement("search").constructor.name
// 'HTMLElement'
zstd という圧縮アルゴリズムを知った
ブラウザとサーバー間でデータを送るときに圧縮するアルゴリズム
有名なのは gzip です
brotli が出てきてからもファイルサイズを示すときによく minify+gzip のサイズが書かれているのを見ます

それ以外に新しいものは特に聞いたことがなかったのですが つい先日 zstd というのを知りました
正式名は Zstandard
Z なので zip 系の標準を目指してるということでしょうか
Meta 製のようです
相変わらず Meta って開発者向けなものを色々作ってますよね
Facebook とかの SNS サービスよりこっちがメインの企業じゃないのと思うほど

Wikipedia によれば zstd は
2016 年に 1.0.0 リリース
2018 年に RFC8478
2021 年に RFC8878

のようで できたばかりの新しいものというわけではないようです
全く知らなかったですけど

ブラウザで使えるなら聞いたことくらいありそうだけど と思って調べてみるとまだブラウザでサポートされていないようです
Chrome では 118 (10/11,12 リリース) で使えるようになるそうです
https://chromestatus.com/feature/6186023867908096

後から追加でサポートするものですし brotli より圧縮率や速度が優れてるのでしょうか?
比較してるサイトを見てみましたが 圧縮率やサイズによって変わってきて 常に zstd の方が良いというわけではなさそうです
yarn の公式サイトが新しくなってた
久々に開いたら新しくなってました
https://yarnpkg.com/
綺麗なイラストもあっていい感じですね

yarn4

ドキュメントのサイトが新しくなるということは大きな更新でもあるのかなと見てみると新しいサイトは yarn4 をカバーしてるということみたいです
まだ rc ですが (といっても rc50) 近々リリース予定なのかもです

これまでの古いサイトは別ドメインになってました
https://v3.yarnpkg.com/

メジャーアップデートで大きく変わるのかなと思いましたが ドキュメントを軽く見た感じでは いつもの yarn2 系のようです
3 からの移行についてのページが見当たらないですし 影響の大きい変更はないのかも

CHANGELOG.md を見てみても一般ユーザー向けだと Node.js の古いバージョンのサポート終了やデフォルト値の変更や UI 改善や高速化などが主のようです
VanJS を htm で使う
VanJS は HTML タグを関数にするというアプローチなので慣れてないと読みづらいです
htm を使うことで lit-html や hyperhtml のような見た目にできるので試してみました

import van from "https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.1.3.min.js"
import htm from "https://cdn.jsdelivr.net/npm/htm@3.1.1/mini/index.module.js"

const h = (type, props, ...children) => van.tags[type](props, ...children)
const html = htm.bind(h)

const App = () => {
const text = van.state("example")

return html`
<div>
<h1>VanJS</h1>
<input oninput=${(event) => { text.val = event.target.value }} value=${text} />
<p>${text}</p>
<p>${() => text.val.length + " chars"}</p>
</div>
`
}

van.add(document.getElementById("root"), App())

いい感じですね
一応メインの方のブログの htmleditor 機能の Example にも追加しています
Biome.js の v1 が出たらしい
Biome というのを見かけました
v1 が出たらしいです

でもこれ何?
そう思って公式サイトを見てみたものの これはなにかという説明がなくいきなりインストールや使い方の説明から
https://biomejs.dev/

サイドバーなどの項目を見た感じはツールがいくつかまとまったもので Lint とかフォーマッターとかがあるみたいです
Rome みたいなやつかな?

そういえば最近見ないけど Rome ってどうなったんだろう?と思って Rome のリポジトリを見に行きました
https://github.com/rome/tools

もうメンテナンスされなくなっていて後継が Biome なんだとか
似てるどころか後継そのものだったようです

Biome のブログの記事として経緯とか書かれてました
https://biomejs.dev/blog/annoucing-biome

Rome ってよくある普通の OSS だと思ってましたが 最初は Meta 傘下の OSS だったんですね
それから Meta から抜けて Rome を開発するための会社を作ったけど その後会社は失敗に終わったみたいです
Biome 作者の人はその会社の 1 社員で その後も Rome に OSS 活動を続けていたけど権限がなくてできることも限られてるので新しいものにしたということのようです
成功と失敗の英語
ステータスや結果として受け取る情報で成功や失敗が入ってるときなんて英単語にするか

名詞の 成功・失敗 だと success / failure
動詞の 成功する・失敗する だと succeed / fail
過去分詞形の 成功した・失敗した だと succeeded / failed

success / failure か succeeded / failed の組み合わせのどっちかかなと思うけど succeeded ってほとんど目にしない
ググっても Windows 系のドキュメントとかが出てくるくらい
じゃあ success / failure かというと failure もけっこうレアな気がする

success と failed もしくは success / error をよく見るような気がする
よく考えると対称じゃない気がするけど 英語が怪しい日本人が作ったものじゃなく 海外のサービスでも見かけるものだし これでいいのかな
npm run で command というコマンドを実行できない
package.json に

{
....
"scripts": {
"c1": "command1"
},
....
}

と書けば 「npm run c1」 で command1 というコマンドを実行できます
この command1 に当たるコマンドは通常 npm などでインストールしたパッケージに含まれるコマンドです

推奨される方法ではないですが 直接 node_modules フォルダ内に .bin/command1 というファイルを配置すれば実行できます

#!/usr/bin/env node

console.log(123)

という中身にします

Windows の場合は command1.cmd のように cmd 拡張子をつけて 中身は cmd ファイル (bat ファイル) にします
.js ファイルを実行するなら node コマンドを呼び出します

Linux の場合はファイルの実行権限が必要なので chmod で追加します

これで 「npm run c1」 を実行すると

root@abc0c5fc3c92:/mnt/88# npm run c1

> 88@1.0.0 c1
> command1

123

のように実行されます

ここで command1 は存在してパスの通っているコマンドやシェルのビルトインと同名でも大丈夫です
例えば

{
....
"scripts": {
"c1": "ls"
},
....
}

として node_modules/.bin/ls にファイルをおけば この ls が実行されます
ファイルの一覧が表示されたりはしません
しかし command というコマンドにした場合 なぜかシェルビルトインが優先されるような動きで node_modules/.bin/command が使用されないです

root@abc0c5fc3c92:/mnt/88# npm run c1

> 88@1.0.0 c1
> ls

123

root@abc0c5fc3c92:/mnt/88# npm run c1

> 88@1.0.0 c1
> command

123 が表示されていません
npm でも yarn でも同じ結果です
Windows では command.cmd を実行するからか問題ないです
たぶん Linux 側の仕様によるものな気がしますが これにハマって時間をとられました
Wireit 思ってたのと違ってそう
OSS の package.json を見てると wireit というキーがあるのを見つけました
なにかと思って調べたら Google 製のツールで npm run を拡張してくれるものみたいです
https://github.com/google/wireit

便利そうなものかなと期待して詳しい機能を見ていたのですが 思ってたのと違ってそうでした
コマンド間に依存関係を定義できて 依存するコマンドも自動で実行してくれたり 並列に実行したりとかそういうのがメインみたいです

またインクリメンタルビルドやキャッシュやウォッチ機能があり そのために各コマンドの入力と出力のファイルを書かないといけないようです
たしかにこういった機能の実現だと必要そうですが これが結構面倒そうです
それに各コマンド側でもすでに持ってる情報なので二重に管理することになり 漏れが出そうですし

また環境変数を設定できるようですが静的な値のみのようです
求めてるのはコマンド実行時に OS 依存せず指定できることなので求めてることはできなさそうです
こういうのがやりたいのです

期待してたのとは違ったので私は使わなそうです
Github アクションとの統合もあるようですし OSS 向けなんでしょうかね
TypeScript ユーザーってサーバーサイドで何使ってるんだろう
TypeScript が使われてるところが相変わらず増えてるなぁと思いながら ふとサーバーサイドって何使ってるんだろうと思いました
やっぱり Node.js なのでしょうか
Deno は TypeScript をサポートしているので TypeScript ユーザーは積極的に移行して Deno が流行るのかなと思ったこともありましたけど 最近はあまり流行ってないようです
そもそも Deno という名前を目にする機会がほぼないです

Deno が npm をサポートしてしまってからはどんどん注目されなくなりつつあるとか聞いたこともあります
たしかに私自身 npm をサポートしたあたりであまり興味がなくなってきましたし
npm を捨てて完全に新しいものという点で興味があったのに 結局 npm を使うなら Node.js でいいやと言う感じです
ライブラリ作者視点でも npm に登録しておけば Node.js からも Deno からも使えるならとりあえず npm に登録となって ユーザーも npm で使えるなら Node.js のままという感じでしょうか

私の場合は TypeScript を使わないので Node.js のままでも全然問題ないですが TypeScript を使う人の場合は変換のひと手間が必要になるので 新規に TypeScript で何かを作るときは Deno にしてもいいと思うのですけどね
TypeScript の普及に比べて Deno があまり普及してないように思うので 何を使ってるのかなと疑問に思いました

ただ TypeScript/JavaScript の記事を思い出してもサーバーサイドとして使ってるのをあまり見ない気もします
みんな基本はフロントのみで Vite や Next.js みたいな既存ツールを使うためだけに使っていて サーバーサイドにはそもそも TypeScript/JavaScript を使ってないのかもしれません
そういう用途だけなら Node.js でパッケージを入れて実行するだけでいいですし
JSX の ?: と && と key
React で条件演算子を使って

<div>
{value ? <Foo/> : <Bar/>}
</div>

みたいなのがあるときで どちらの場合も同じコンポーネントになる場合は注意が必要です
上の場合の Bar も Foo になっていて value 問わずコンポーネントは Foo になり props の違いだけの場合
こういう記法の時点で書く側は別物のつもりだと思いますが React が認識する ReactElement のツリー構造ではどっちも同じ Foo です
なので props が変わっただけという扱いになりコンポーネントはアンマウントされず使いまわされます
基本は props が変わればそれに応じて表示も変わりますが中で state を持っていた場合には state が引き継がれることで予期しない動きになります
その対処のために key を指定する必要があります
key が変われば同じコンポーネントでも別物扱いになり 既存のコンポーネントがアンマウントされ新規のコンポーネントがマウントされるので state はクリアされます
key は配列を返す場合に使うことが主ですが それ以外で必要になるパターンです

これをみると

<div>
{value && <Foo/>}
<Foo/>
</div>

のように条件付きで表示する場合 これも key がないとズレてしまいそうに思います
value が false から true になって Foo が 2 つ並ぶようになるとき それまでにあった常に表示されている Foo は 2 つめになり新しい Foo が先に来るはずです
でも React 的には Foo が 1 つから 2 つになっただけで順番的に最初の Foo が使い回されるのじゃないかと思いました
しかし試してみるとそういった事は起きません
期待通りに新しい Foo が先に挿入されます
どうなってるの?と思いましたがよく考えてみると 表示しない場合でも {} の中に undefined や null が残ります
これを無視しなければどこに新しく追加されたか判断できそうです
なので 配列以外で key を考えないといけないのは ?: くらいで && の場合は気にしなくても大丈夫そうです

{} に undefined を残さずひとつにまとめてこういうことをする場合は期待する通りには動きませんが これは配列を使ってるわけなので key が必要なケースです

const Component = () => {
const elems = []
if (value) elems.push(<Foo/>)
elems.push(<Foo/>)
return <div>{elems}</div>
}



?: に key を使うとき 同じ階層で同じコンポーネントの場合 key が重複しないよう注意が必要です

const App = () => {
const [state, setState] = React.useState(false)
return (
<div>
<button onClick={() => setState(!state)}>switch</button>
{state ? <Foo key={1} value={1}/> : <Foo key={2} value={2} />}
{state ? <Foo key={2} value={3}/> : <Foo key={1} value={4} />}
</div>
)
}

1 つめの {} と 2 つめの {} では完全に別物のつもりですが同じコンポーネントで階層が同じなので 再レンダリングの前後で同じ key が別の場所にあると使い回されます
state を切り替えると key の 1 と 2 が入れ替わるので 配列の並び替えと同じ扱いになります
配列でラップしたり <></> でラップすると展開後に階層が同じであっても 別階層として扱えるので key の重複がありえそうならラップしてしまうと安全です

<div>
<button onClick={() => setState(!state)}>switch</button>
<>{<Foo key={state ? 1 : 2}/>}</>
<>{<Foo key={state ? 2 : 1}/>}</>
</div>
<div>
<button onClick={() => setState(!state)}>switch</button>
{[
[<Foo key={state ? 1 : 2 }/>],
<Foo key={state ? 2 : 1 }/>,
]}
</div>

同時に同じ階層に同じ key が出現した場合は 作り直しや使い回しが意図したとおりにならないだけでなく表示もおかしくなります
例えばこの場合 state が変わるタイミングで同じ要素が繰り返し作られて要素が増えていきます

<div>
<button onClick={() => setState(!state)}>switch</button>
{[1,2,3].map(x => <div key={state ? 1 : 2}>{x}</div>)}
</div>

こういう同時に同じ key が存在するケースはコンソールに key の重複エラーが出てるので気づけるはずです
同時ではない場合は正規の入れ替え目的として扱われてエラーにならないので見逃しやすいです