📋

モダンフロントエンドに古代技術を組み合わせた掲示板を作った

に公開

箱庭諸島の中にはチーム戦でやるタイプがあるのだが、ありがたいことに同じ陣営とやりとりしたり、他の陣営へ外交ができる専用掲示板が付属されている。
その掲示板を1から開発したというお話。

経緯

簡単にまとめるとこう

  • 箱庭諸島のフルスクラッチを決断した。フロントエンドはReact。
  • ただアマグラマーなのでいきなりフルスクラッチは不可能
    ※jQueryだけかじった程度、cssにもフレームワークがあるのを知らなかった、git,githubは名前こそ知れど使ったことない等々
  • 使用している陣営掲示板が2種類あった。そのうち1つをする改修予定だった。

陣営掲示板を題材にして現代の開発手法を覚えるのがちょうど良さそう
という結論に至った。

今までの掲示板

同じものをそのまま作り直すのでは意味がないので、現在の課題を把握したうえで新しく画面設計することとした。
ただReactを触ったことがない以上コードの設計はしようがないので、作りながらやっていくことにした。

現在使用している掲示板

(開発者のあっぽーさん勝手にすみません)

もう1つはYY-BOARDというフリーの掲示板を使っているのだが、こちらのほうがわかりやすいためメインで使用していた。あくまでこの2つを比較しての話。
まず今の掲示板をいくつか列挙する。

返信の方法が非常に分かりづらい

真ん中辺りに返信、編集、削除のラジオボタンがあるのでこの辺かな~というのはわかる。
しかし返信を選択して直下の実行ボタンを押しても画面が更新されるだけで何も起きない
この時点で返信方法がわからない人が過去に出ている。

よく見るとその下に●返信は投稿記事の「選択」をチェックしてパスワードは入力しないで実行ボタン押下(複数選択可)と書いてある。ちゃんと読もうね。
と言っても昨今の人間はそういう注釈は大体読まない。予防線を張るために書いてると言っても過言ではない(?)
しかもこの「選択」、マウスカーソルがちゃんとポインタになるのだが、押しても何も起きない。チェックボックスを直接押さないと意味がない。
初見殺しの2重トラップを理解すれば返信できるとはいえ、現代においては非常に分かりづらい。

編集・削除の方法が非常に分かりづらい

返信とほぼ同じだが、実はこちらにはもう1つトラップがある。
投稿するときにパスワードが設定できるのだが、実はこのパスワード設定、任意である。
何も知らず投稿してしまうともう二度と編集や削除が出来ない。(省略可)とは書いてあるが、省略したら編集削除が出来ないよとはどこにも書いてない。非常に分かりづらい。
(余談だが、個人的にはネットだろうと発言に責任持て、誤字脱字なんて愛嬌の一つ、と思うのだが、discord鯖で編集削除の禁止を検討したところ猛反発喰らったことがある)

強いて言えば複数同時に削除出来るのが便利くらい。返信と編集は同時に出来たところで…

画像が添付できない

これは掲示板だと割と普通なのだが、残念なことに現在はSNSが主流である。ということは画像の添付ができて当たり前。
そもそも他人と連携するのにスクショ画像無しで細かい座標を指示するのはなかなか骨が折れる。そのためdiscordなどの他チャットツールがしばしば使用されている。

プレイヤー視点だと外部ツールの使用は気にならないのだが、これが管理人視点だと割と大きな弊害となる。
私が運営しているところではゲーム終了後に全ての陣営の掲示板ログを公開しているのだが、細かいやりとりは別アプリへ流れてしまい、掲示板に残らないためログを見返す価値が損なわれてしまう。
個人的にはゲーム内の掲示板で完結してもらい、いつどんな感じでやり取りが行われてたかの答え合わせや雑談ネタとしたい。

画面更新が都度入る、過去スレッドに返信しても気づかない、未読のNewを消すのが手動などなど

細かいところを挙げれば色々でてくるのだが、まあ20年前のスクリプトだから致し方なし…

新しい掲示板

画面

作り直した結果がこちら


画面設計を進めれば進めるほど(これほぼ𝕏じゃね…?)となってしまったので、むしろ開き直って近い感じにした。

メッセージの配置や色合いは今までの掲示板に近い雰囲気を踏襲し、全く違うツールを見たときに起こる拒否反応を少しでも起こさないように配所した。
説明しなくても直感でこんな動作になるだろうな、がUI/UXとして理想な形であるので、そうなっていることを信じてあまり説明はしない。
慣れれば使いやすいは典型的なだめなやつだって誰かが言ってた。

環境

別にnoteでもいいような内容が続いたのでここからエンジニア寄りの話を展開する。
まず開発するためにやったことは以下。

  • node.jsを導入
  • Reactを導入
  • Viteを導入(序盤)
  • ESLint、Prettierの設定(序盤)
  • TailWindを導入(中盤)
  • git、githubを導入(中盤)
  • huskyの追加(中盤)

何も知らなかったので最初は2つだけだった。
こういうのがある、と教えてくれる有志がいてくれて、開発しながら色々便利なやつを導入していけたのはだいぶラッキーだと思っている。謝謝茄子。ただ数ヶ月頭パンクしかけてた。

そしてバックエンドも含めた主な環境とフレームワーク,ライブラリは以下

node v20.14.0
vite v5.4.1
react v18.3.1
react-redux v9.1.2
tailwindcss v3.4.10
AN HTTPD v1.42.0
perl v5.26.3

昨今では恐らくよく使われている言語を使っている。至って普通!

開発にあたって苦労した箇所

掲示板っぽくも掲示板っぽくない挙動が2つ。

  • 画面更新がなく投稿が出来る(=非同期通信)
  • スレッドを一番下までスクロールすると次のログを自動で取得する(=無限スクロール)

何を当たり前なことをと思われそうだが、結果的にSNSライクな掲示板になった。

別のチャットツールを利用していてもメッセージ数は600件を超えてくるので(3,4人でのやりとり)、1000件以上なら分割読み込みでユーザビリティを損なわないようにするには必須。非同期処理はかなり難しいものと思われた。
ただそこは現代開発。ReactとAIの力で数日で実装できた。すごい。

一番の苦労はバックエンド。CGIで擬似APIサーバーを実装した。
理由は現行のレンタルサーバーに設置して動かさないと意味がないため。主にバックエンド周りでてこずった点を列挙する。

GET,POSTしかない

厳密にはPUTなどもあるのだが、POSTDATAが受け取れないという仕様があるらしい。マジカヨー
https://nakajiman.blogspot.com/2008/02/perl-cgipm-put-post.html
なのでGETはそのまま、POSTのエンドポイントにPUTやDELETEの処理を入れるという強引実装をした。
見た目はよろしく無いが、背に腹は代えられないので致し方なし。

型宣言がない

perlは良くも悪くも型宣言がない。正直要らんだろと思っていたのだが、JSONを扱うことによって初めて型の重要さを知った場面があった。

# log追加処理
my $newNo = 0;
foreach my $message (@{$bbsTable_log->{$campId}}) {
    if ($message->{"No"} > $newNo) {
        $newNo = $message->{"No"};
    }
}

新しいメッセージが投稿された際に、一番大きなNoを新しく割り当てるためのループ
(Noだけの一次元配列を作ってmaxで抜き出すとか、Noを大きい順にソートして先頭の配列を抜き出すとかのほうが良かった気がするが、例としてこのままにしておく)

色々あって(記憶がない)JSONのNoには文字列として保存しているのだが、if ($message->{"No"} > $newNo)で比較すると、自動的に型がstringからnumberへ変換される。SV構造体が変化してしまっているらしい。マジカヨー
https://gihyo.jp/dev/serial/01/perl-hackers-hub/001601
これに関しては特に修正しなかった。将来的にperlから脱却する予定があるため。
React側の条件式を===から==にして型を無視することで誤魔化した。許せサスケ、これで最後だ(?)

安易に画像が保存できない

画像をアップロードできるようにするなら、その画像が悪意のあるものじゃないか確認する必要があるというセキュリティの話。
https://blog.flatt.tech/entry/file_upload_security
これがなかなかに面倒。ファイル名のサニタイズ、画像サイズチェック、拡張子チェック、画像のパーミッション設定、個人情報対策にExif削除、場合によってはカラープロファイルの統一等々…
加えて複数枚の画像アップロードに対応させているので、1枚でも不適合な画像があった場合は投稿自体を失敗させるようにした。
画像チェックメッセージ処理画像保存と保存を一番最後に持ってこないと、投稿自体は失敗しているのに画像だけがサーバーに保存されるという現象が起きてしまう。
この辺の諸々の処理は自力での実装とImageMagickを使用することで対応した。というかImageMagickは有志にモジュールとしてほとんど作ってもらった。

windows環境が合わない

本当はLinux環境で開発するべきなのだが、そこまで手が回らなかったのでwindows環境のまま開発を続行した。
しかしImageMagickを使用したことが原因でwindows環境だと安易に使えなくて開発効率が落ちた。
https://naotoshisami.com/2021/12/imagemagick-install-win10/
主にはwindowsこの辺の内容。
もうひとつはC:Program Filesにインストールしてしまったので、スペースを考慮した書き方にしないといけなかったこと。
途中からWSL2で開発すべきというのを教わったが、そんなもの知らないから開発をしていないのだ。

DBが使えない

使えないわけじゃないが、箱庭諸島がファイルを1行ずつ読み込んで値を格納する古代技術のままであり、ゲームが終了した箱庭諸島はアーカイブとして再公開する運営をしている。
そのため新たに組み込むとアーカイブする際のデータ管理が複雑になる可能性があったため、管理コスト削減のために踏襲する必要があった。

ちなみに使用しているサーバーはさくらのレンタルサーバのライトプランなので、Mysqlは使用できずSQLiteしか使えない。
でも数千人も遊ばないからSQLiteでいいんじゃないかなぁと思わなくはない。

常駐プログラムが使えない

これも使えないわけじゃないのだが、レンタルサーバーの規約の問題になる。
つまりリクエストがあったら都度スクリプトを起動する古代形式にしないといけない。
開発中は常駐プログラムで作成していたので、レンタルサーバーに適用する際は有志に相談して解決出来た。謝謝茄子…

ちなみに関連しているかわからないのだが、レスポンスヘッダーのステータスは"HTTP/1.1 200 OK\n";で問題なかったのに、レンタルサーバー上では"Status: 200 OK\n";としないと動かない事象があった。マジわけわからん。

終わりに

バックエンド側の話をメインとしたが、React自体も初めてでコンポーネント型開発は慣れるまでかなり苦労した。
かなり時間はかかったが現代フレームワークにperlかつCGIで疑似的なAPIサーバーという古代技術を組み合わせた陣営掲示板が出来上がった。

初めての言語に手を出して完成するまで約半年。有志とAIがいなかったらきっと1年くらい開発して断念していたと思う。
このあとはまだTypeScriptやNext.jsやpythonや仮想環境の構築などなど覚えることがいっぱいあって既に嫌になっているが、程々に励んでいきたい。
記事を書いたタイミングではまだ導入はしていない。今までの掲示板よりは使いやすくなったと感想をいただけることを祈るばかり…

SNSライクな美しい見た目をしてるくせに、中身は20年以上前の技術で動いている。
これはアプリ界のバ美肉おじさんと言えるのではないだろうか。

Discussion