🧊

preactjs/wmr について

GitHub - preactjs/wmr: 👩‍🚀 The tiny all-in-one development tool for modern web apps.

これです。

WMRとは

The tiny all-in-one development tool for modern web apps, in a single 2mb file with no dependencies.

とのこと。

READMEを見る限り、`wmr start`と`wmr build`でそれぞれdevとprod用のコマンドを提供してくれるCLIツールらしく、`preact-cli`と何が違うんや?とか、それこそParcelとかViteとかと何が違うんや?と思ってた。

で、あれこれ調べてると、中の人(`@_developit`氏)が熱く語ってるPodcastを発見。

というわけで、それをざっくりまとめたのがこの記事です。

JS Party #158

Waldo's My Roommate? featuring Jason Miller and WMR (JS Party #158) |> Changelog

WMRってどういう意味?

  • 当初はHMRをもじって、Warm Module Replacementって呼んでた
    • ただ今となっては、Web Modules Runtimeって呼んだりも
  • まあアルファベットの並びに特に意味はないのだ

ちなみに発音は、「だぶりゅーえむあーる」らしい。「ぅまぁ」じゃなかった。

モダンなウェブアプリとは?

  • あなたが最近取り組んでるプロジェクトのこと
  • より最新の仕様やコードで書かれたアプリのこと
    • ES Modulesが動くES2017以降くらいの
    • もちろん古いコード資産もサポートしたいと思ってる
    • けど、よりフォーカスするのは最新のもの

既存のツールでいうと?

  • CreateReactAppとかNextとかwebpackみたいなもの?
  • webpackに近いといえるけど、微妙に違う
  • 最近でいうならViteとかのほうが近い
    • ほかにもSnowpackとかWeb Dev Serverとか
    • ES Modulesファーストな開発ツールということ
  • 思想としてはPercelのほうがわかりやすい
    • コードだけ書けば、それに必要なバンドラーの設定などを勝手にしてくれる
    • 限られた時間の中で、バンドラーの設定に時間を費やすべきではない
  • Microbundleというビルドツールも作ったけど、あれは逆の発想
    • ありとあらゆる恣意的なRollupの設定を適用するバンドラーだった
  • そうではなく、コードベースを調べ、必要な設定だけを使ってバンドルする思想
    • ビルド時にはRollupを使ってる

Parcelって久しぶりに聞いた気がする・・!

開発時はバンドルしない

  • ビルド時はRollupだったが、開発時はバンドルしない
    • このへんがViteとかに似てる
    • 互いにいくつかの機能は統合したほうがいいかも?みたいな話もしながら開発をはじめた
  • 開発サーバーへのモジュールのリクエストに応えるだけ
    • すべてをバンドルして返すのではなく、それぞれをHTTPリクエストで処理する
  • Babel互換のASTトランスフォーマーと、Rollup互換のプラグイン機構を自作した
  • 全コードベースのグラフを構築するのではなく、トークンにするだけ
  • glitch.com のStaticモードをより良くした感じを目指してはじめた
    • `npm i`せず、コード中にいきなり`import`を書いても、それが動く
    • 裏でnpmからtarを直接ストリーミングして返してる
    • 必要なのはコード自身と型定義くらいってわかってるし、それもディスクに書き込まない
  • もちろん、読み込めないモジュールも世の中には存在する・・・
  • 初回は直接ストリーミングするけど、裏で圧縮したものをディスクに書いておく
    • Rollupを通すだけなので速い
    • 次回以降のリロードやHMRでは、より速くモジュールを届けられる
    • モジュールは個別にレスポンスするのではなく、まとめて最適化して返す
  • CJSとUMDのモジュールも、ESMに変換して返してる
    • 内部的に、`npm`のモジュールの場合は、`/@npm/foo`みたいなパスで`import`できるようになってる
  • 拡張子も自動で判断して、必要ならばトランスパイルする
    • ブラウザの`import`の仕様に沿いたいし個人的にはしたくなかった
    • けど、世の中的に必要であろうと判断した
    • もちろん拡張子を指定するほうが処理の無駄が減るので速く動くはず
  • WMRのコードは、JavaScript + JSDocの型定義で書かれてる
  • あとはCSS Modulesや、一部のプレフィックス付き`import`もできる
    • TSの場合は、そのエイリアスを定義した`tsconfig`を生成する

`package.json`なしで開発できるのいいけど、それはそれで問題も出てきそうよね・・。

WMRとPreactの関係は?

  • `npm init`や`create-wmr`が生成するテンプレはPreactが使われる
    • これはPreactを使えということ?
  • Preactが必須というツールでは決してない
    • 自分たちがそういうツールがほしかったからそうなってるだけ
  • 軽量なコードでプロトタイピングを手早くやりたかったという経緯
    • ここしばらくはバンドラー界隈を傍観していた
  • それができるものがなかったので
    • 最近になって、ES Modulesが使えるようになり、それを使いたいと思うようになった
  • Googleでの仕事として、ExportMapを広めることに注力してきた
    • これによって、バンドラーがそのパッケージが最新のコードを使ってるかどうかがわかる
    • 同時に、古いコードも共存させられる
    • これを前提とするのはどうかと思った
  • ES Modulesが前提であれば
    • HMRもクエリパラメータでキャッシュを飛ばすだけでいい
    • HTTP/2のローカルサーバーで開発もできる
    • ユーザーが書いたコードが、そのままブラウザで実行されるようになる
    • これまでの`import`は、実際には裏で変換されたコードを読み込んでいた
  • WMRはPreactには依存していない
    • 内部的には、20くらいのRollupプラグインでできてる
    • いくつかの非公開の自作モジュールがあるが、すべて独立したもの
    • たとえばViteからそれらを使うこともできるはず
    • ExportMapを解釈する実装は、他のツールのものよりも良くできてると思っていて、npmに公開することもできる
  • ただPreactをデフォルトにすることで、機能を実装するための実験台にしてた面はある
  • 最近事前レンダリングCSSの最適化の機能などを追加したしたけど、これもPreactとは関係ない
    • `prerender`という関数を定義して、文字列を返すというだけ
  • ReactでもVueでもSvelteでも、それ用のテンプレを作ることは簡単にできる
  • WMRをフォークするよりは、プラグインとして実装してもらえるとよい
    • そうすればまた別の誰かがコラボレーションできる

コラボレーションと競争

  • コラボレーションを推奨するなら、新規ツールを作る理由は?となる
    • このあたりの線引についてどう考えているか
  • これは難しい質問
  • ExportMapの実装は、自分が要約として公開する価値があるものだとは思う
  • Babel互換のASTトランスフォーマーも作ったけど、コミュニティとしては必要ないかもしれない
    • たぶん必要ない
    • JavaScriptではなく他の言語でもっと速く動かせないかという動きもある
    • `esbuild`を試したこともあるけど、非常に高速だった
    • 可能性は感じたけど、結論としては自分たちのニーズのために自作した
  • うまく言えないけど、このあたりにその答えがある気はしている

これは難しい話よね・・。

実用性としては

  • プロトタイピングや開発に便利なのはわかった
  • けど、複雑なアプリを作って本番公開したりできるか?
  • 答えとしては2つある
  • まず、新しいツールであるということ
    • これはどんなツールにも言えることではある
    • つまりはどこかにバグが潜んでいてもおかしくない
  • もう1つは、ES Modulesベースのスタイルがどれほど実用性に耐えうるかということ
    • これはまだはっきり言えない
    • 10000くらいのモジュールを使ってる場合、HTTP/1ではきっと遅くて使えないはず
    • npmのモジュールはキャッシュされるし、頻繁に増減もしない
    • しかしユーザーコードは、それぞれのソースファイルに対応する
  • 本番ビルド時は、WMRはただのRollupになる
    • 独自の互換プラグインを実行することもない
    • Rollupは本番でもよく使われてる
  • ビルドするだけが本番デプロイではなく、そこにはプロキシなどのミドルウェアなどが必要かもしれない
    • だからwebpackを使ってる人たちも多いはず
    • それはまた別で考えるべきことではある
  • WMRには`start`コマンドがあり本番サーバーを立てられるが、それを推奨はしない
    • 自分でNodeのサーバーを立てるのではなく、CDNなどからHTTP/2を利用することがベター
    • ローカルで、できる限り近しい挙動を再現するために同梱してあるだけ

WMRはスタックではない

  • Next.jsのようなサーバーで動作させるものでもない
  • そこには明確な線引がある
  • WMRとしては、静的なファイル生成に終始する
  • たとえばEleventyからWMRを使おうとしている人がいるのを知ってる
    • WMRのミドルウェアからEleventyにプロキシするか、EleventyからWMRを指す`script`タグを使うか
    • 後者のほうが適切
  • Eleventyを使ってない場合、ファイルベースのルーティングがやりたくなるかもしれない
  • WMRは低レイヤーなものなので、やればできることは多いけど、それらが目的ではない

なるほど!

というわけで

雑にいうと、Viteと同じような開発体験が得られるESMベースの開発ツール。

ただ内部的には違ってて、互いに参考にしながら切磋琢磨していくのであろうなあ・・と思った。

Viteの2.0におけるRollup互換のプラグインシステムは、WMRインスパイアって書いてあったし。

Comparisons with Other No-Bundler Solutions | Vite

個人的には、Preactを使ったアプリをサッと作りたいなら、とりあえず採用していいのかなと思った。
動作も軽いし、設定ファイルいらずで即コードが書き始められる体験はやっぱり良いので。

ViteからPreactのテンプレを使っても、だいたい同じようには動くんやろうけど・・。

それ以上は結局SveltKitやNext.jsやら、それら特有のあの機能が欲しいから使うみたいになりそう。

世はNon-bundler戦国時代に突入するのだろうか!