[JavaScriptから現実世界に干渉する7の方法: ブラウザでハードウェアをコントロールする技術]

JavaScriptから現実世界に干渉する7の方法: ブラウザでハードウェアをコントロールする技術という本を書いてみた。前々からこのテーマでまとめた一冊というのを作りたかったので勢いで書いた。サンプルコードもほぼ各章ごとに、そこそこすぐ試せる形で用意したりして工夫してみた。

JSから直接ハードウェアをコントロールするのが好きなのと (特に WebSerial/WebUSB)、もともと WebAudio が好きだったのもあるので、これらを包括的に「現実的に干渉する」というまとめにすることにしてみた。そうなると「ディスプレイ」(光)」も無視できないので、光→振動→音→(HID→MIDI)→Serial→USB とより低レベルになるような構成にしてみた。

直前にいろいろ一気に書いたけど、だんだんやりかたをアップデートした結果、これが一番図とサンプルコードに気合が入っている。

1月3日17時〜7日の17時までは無料に設定してみたので眺めてみてください。

  1. トップ
  2. tech
  3. 『JavaScriptから現実世界に干渉する7の方法: ブラウザでハードウェアをコントロールする技術』という本を書いた

この日記システムを golang で書きなおした。元日から4日ぐらいかけた。なんかおかしかったら教えてください。

前々から日記システムをgolangにしたいなという気持ちを抱きつつxatena-goを書いたりしていた。しかし実際全体を移行するという気がなかなか起きなかった。というのも Hatena記法だけじゃなくてMarkdownだったり素のHTMLだったり、tDiary記法だったりをそのままDBに入れていたり、類似エントリ機能とか、類似画像機能とか、それらを実行するジョブキューとか、なんか細けえ最適化 (linkヘッダとか) が入ってたりとか……

最初のとっかかりが重要、ということで、既存のDBそのままで閲覧側だけまず作り (表示するだけだから特にフォーマッタとかは関係ない)、一旦安心しつつ書きこみ系を実装していった。大きな変更は主に Claude Code で計画させて割と自動で実装してもらい、Claude Code の Limit がきたら、細かいレビューしたり、小さい変更は Gemini CLI で補完した。

無駄に元のスキーマで DATE や DATETIME をつかっていたせいで (SQLite ではTEXTと一緒)、これらを go-sqlite3 が「いい感じ」に time.Time に変換するので、若干ややこしいクエリに書きかえたり、最小限のマイグレーション (created_at などを TZ 付きのフルのISO 8601に) をかけた。

サーバサイドで主につかったもの

  • sqlc backtick のエスケープに対応してない?のが罠なぐらい?
  • echo 特に気になるところない。HideBanner = true ぐらい

管理画面

自分しか使わない管理画面をリッチに作る気がさらさら起きなかったので、今までは1つの「編集」画面しかなかった。十分といえば十分だけど予約投稿機能が実はあるので、それを管理するのが面倒なのと、ジョブキューの見える化をしたかったので、新しく作った。

編集画面は、元々は Polymer による Web Components 実装だった。なので、最初は Lit で Web Components を書き直したけど、どうしても HTML in JS が許せないので、やっぱやめて使ったことない Svelte にしてみた。

Svelteも最初は Web Components モード (SvelteはSPAを念頭にしてるが、そういうモードがある) として使ってたけど最終的には管理画面全体で SPA として再構築した。

といってもほとんどこれらの「あっちこっち」の書き換えは Gemini CLI でやったので特にまだ Svelte の特徴を感じてはいない……

Gemini CLI はなんか Lit は Google が推してるから安心ですよみたいなこと言ってきたので「PolymerやAngularJSのこと考えると Google が推してるからといって安心ということはない」と言ったら Svelte がこの手の小さいやつだと最適とか本当に適当なことをいう。

PSS (Proportional Set Size) = 実質的な消費量

smem というツールを使うと実質的な消費量が簡単に見れるらしい。知らんかった。preforkモデルだと copy on writeを考慮した実質的なメモリ消費量が top や ps だと簡単にわからないので便利だ〜

smem -P "/srv/www/backend.psgi" -t -k
  PID User     Command                         Swap      USS      PSS      RSS 
2438110 cho45    /srv/www/backend.psgi (mast        0     6.0M    10.9M    50.0M 
2438111 cho45    /srv/www/backend.psgi (work        0     6.8M    10.9M    49.4M 
2438114 cho45    /srv/www/backend.psgi (work        0     7.5M    11.2M    49.1M 
2438205 cho45    /usr/bin/python3 /usr/bin/s        0    11.0M    11.3M    13.7M 
2438118 cho45    /srv/www/backend.psgi (work        0     7.8M    11.4M    49.4M 
2438119 cho45    /srv/www/backend.psgi (work        0     8.5M    12.2M    50.2M 
2438120 cho45    /srv/www/backend.psgi (work        0     8.7M    12.3M    49.6M 
2438117 cho45    /srv/www/backend.psgi (work        0     8.7M    12.3M    49.7M 
2438112 cho45    /srv/www/backend.psgi (work        0     8.9M    12.4M    49.7M 
2438113 cho45    /srv/www/backend.psgi (work        0     8.8M    12.6M    50.5M 
2438115 cho45    /srv/www/backend.psgi (work        0     9.3M    13.0M    51.1M 
2438116 cho45    /srv/www/backend.psgi (work        0    17.9M    21.6M    57.8M 
-------------------------------------------------------------------------------
   12 1                                           0   109.8M   152.0M   570.1M 

PSSの合計が重要で、この場合152MB使っている。

  PID User     Command                         Swap      USS      PSS      RSS 
2498750 cho45    /usr/bin/python3 /usr/bin/s        0     9.8M    10.1M    12.2M 
2498688 cho45    /srv/www/lowreal.net/Hanran        0    17.8M    17.9M    19.6M 
-------------------------------------------------------------------------------
    2 1                                           0    27.6M    28.0M    31.8M 

移行後はそもそも1プロセスにした。やたらメモリ使用量減ってくれた。

  1. トップ
  2. tech
  3. 日記システムPerlからgolangに書き換え

日記のバックエンド系のコンポーネントだけ daemontools を使い続けていたけど、移行したことによって完全に無になった。

あんまりアクセスログとか見てなくて気付かなかったけど、GPTBot/1.3 が 5req/sec ぐらいでずっとアクセスしてきていて謎い。そんなにずっと辿るほどのエントリ数はないだろ……

システムあたらしくしたのでどんどん使っていくぞ〜

ポケモンZAはスタッフロールみるところまでやりました。

Chemr に mcp を実装してみて、はじめて自動的に役に立った。具体的には Gemini CLI が golang の MarshalXML でクソみたいな推測でモノを言うから検索しろと言ったらちゃんと最速で必要なドキュメントに辿りついた。「CDATA にはするには独自実装するしかない」と言い張っていた (そんなことはなく構造体タグにオプション書くだけ)。

というか別に Google Search がちゃんとしてればこんなMCPいらないはずなんだよな。誰だか知らねークソエントリをトップに出して公式サイトの順位を下げる(あるいは一切表示しない)というクソサーチエンジンが悪い。

LLM に我々(誰)が必要な図を描かせる場合、今のところは「matplotlib で描け」と指示するのが良さそう。特に↑のように2つのグラフの関係が正確であってほしいときは強力。

こういうのとかも: https://github.com/cho45/Hanrangon/blob/main/docs/frontend_arch_diagram.png

ただデフォルトのままよりは、ちゃんと Noto Sans JP を入れて使ってもらったほうが数段上に見える。

Mermaid で描かせてたけど、それほど表現力が高くないので最初からコードで書かせたほうがいい。まず人間が伝えるためのプロンプトとして Mermaid はいいかもだけど、自然言語でも伝わるしなあ

1月1日にインターネットが数度不通になってやきもきした。

Gemini CLI が急に無応答になったと思いきや、ネット全般に繋がらない。今までよくあった DS-Lite の NAT 枯渇のような症状ではなく、IPv6 も全滅。一応 VDSL モデムとかルーターの再起動をしてみたけど、関係なし。まぁずっと安定してるしLEDも正常だった。

ということで、これはまたかつての固定回線異常を彷彿とさせるなと新年早々に気分が重く。

問合せ方法とかを調べていたら自動的に復旧したので良かった、と思いきやまた数分切断とかとなって嫌な感じだった。結局 NTT 側の障害だった (結構この障害情報も遅れて表示されるので、当日の夜にようやく原因がわかった)

とりあえず2日〜4日は大丈夫だった。

Makefile で複数のプロセスを起動させたい(けど同時に終了してほしい)とき以下のようなイディオムがあるのを知った。foreman とかないと面倒だと思ってたわ

run-with-fe-dev:
        trap 'kill 0' EXIT; \
        (cd admin-frontend && npm run dev) & \
        HANRANGON_FE_DEV=true go run -tags "$(GO_TAGS)" .

Makefile というかシェルの機能だけど、EXIT をトラップして kill 0 (プロセスグループにシグナルを送る = 起動したシェル以下のプロセス全部が死ぬ)

node あるなら concurrently が一番楽なのかな? 名前が長いよな…… あとは高級なやつだと mprocsがある? ほかにもあるんだろうか