☁ SPAをやめたい (やめられない)

React + TypeScript でウェブアプリを作っているけど、シングルページアプリ(SPA)をやめたい。いまはやめられない。SPAのメリットとデメリット、他の方法を軽くみてみる

SPAのメリット

  • 性能:
    • 小さい更新が速い
    • ページ遷移も (ウェブページ間の移動に比べたら) 速い
  • 開発効率:
    • 作りやすい。普通のデスクトップアプリの感覚で作れる
    • Next.jsを使うとライブリロードとかが自動でついてくるし、Webpackの設定などもほとんどやらなくてよい。嬉しい
    • ブラウザの開発ツールがとても便利

なおReactでもVueでもそこまで大きな違いはなさそうだと思っている

SPAのデメリット

  • スタートアップ性能:
    • ページ訪問時、ライブラリのロードが重い
  • 開発環境の複雑性:
    • 非常に複雑
    • 普段は気にしなくていいが、問題が起こったときは内部を覗くこともある
    • モジュールシステム (CommonJS/ESModule) はしばしばひっかかる
  • ブラウザ機能の再実装:
    • ブラウザが標準で備えてる機能を再実装している部分があり、無駄
      • 履歴管理・クライアントサイドルーティング
        • (作りが甘いと / 以外に訪問できなくてブックマークが機能しなかったりリロードすると壊れたりする)
      • リンククリック時の遷移
        • (作りが甘いとミドルクリックで新しいタブが開かなかったりする)
      • スクロールのリセット・復元
        • (作りが甘いとページ遷移したのにスクロールが下のほうのままだったりする)
      • など
  • ブラウザ間の差異:
    • ブラウザの種類・バージョンによって挙動が異なることがある
    • IE対応をしない場合、問題は大幅に軽減される
      • しかし Firefox vs. Chrome だけでも問題になることがある

解消しつつある問題

  • 環境構築がつらい:
    • Next.jsで満足しつつある
  • CSSがつらい:
    • TailwindCSSで満足しつつある
  • 状態管理がつらい:
    • React Hooksで満足しつつある
    • 初期データの入力が難しかったが、Next.jsが勝手にやってくれることに気づいた
    • 思えばデスクトップアプリでもつらかったし従来のウェブアプリでもつらかった

別案: 非SPAなウェブアプリ

  • 従来のHTMLを動的生成するやつ。(典型的にいえばjQueryを使うやつ)
  • ページ遷移が遅い
    • ブラウザからするとHTML/CSS/JSをいちから読み直させられているので仕方ない
  • 状態管理がめんどくさい
    • ページを移動するときの状態の持ち運び
    • ページ内の状態の管理と反映
  • 一部のページだけReactで動かすのは両方のデメリットを被るのでよくなさそう (試してはいない)

余談: サーバーからクライアントにデータを送りこむときは <script data-json="{データ}"></script> で埋め込んでおくとうまくいく。JavaScriptの動的生成はすべきでない

別案: ネイティブアプリ

  • 作るのも配布するのも大変そう。あまり検討していない

その他: TypeScript

TypeScriptに関する細かい話題

  • 良いところ:
    • 静的型がついて網羅性検査まである
    • VSCodeのインテリセンスが強い
    • セマンティクスがJavaScriptと同じ
      • JavaScript基準の資料とギャップがない
  • コンパイルが遅い:
    • ビルドするとき型検査しないようにするとよさそう
    • バックグラウンドでコンパイラ(tsc)を動かしておく
      • (バンドルと型検査を並列で行う)
  • nullとundefinedを区別するのが難しい:
    • 常に片方だけ使い、可能なかぎり区別しないコードを書くとよさそう
    • 比較は x != null で行う (!== ではなく)
    • Next.jsにundefinedはダメといわれることがある
      • JSONに変換したときラウンドトリップしないため
      • オブジェクトをトラバースしてundefinedをnullに書き換えるヘルパーでカバーできる
  • 演算子の挙動がおかしい:
    • 数値 + 文字列 とか
    • 文字列連結はテンプレートリテラルで書くとよさそう
    • ==/!= は使わないとよさそう (ESLintのeqeqeqを使う)
    • それ以外はいまのところ気をつけるしかない……
      • 演算子は危険という認識
  • ライブラリの型定義がたまにおかしい:
    • 型定義を自分で書くか、型安全なファサード (safe wrapper) を挟む
  • 型システムが健全でない:
    • インターフェイスにanyが出現しないように書くとよさそう
    • Rustのunsafeみたいなものだと思っておく