Symfony Advent Calendar 2020 day8の記事です。(2ヶ月も大遅刻!)

Symfony World初日の基調講演とそれに続くセッションで発表されたSymfonyUXについて、使ってみた方は既にいると思いますが、

  • SymfonyUXとはなにか
  • なぜSymfonyUXが作られたのか

については当日の講演を聞いていない方には十分に伝わってないと思われたので、大遅刻ですが「使ってみた」だけでなくなにか・なぜ作られたのかについてもまとめた記事を書こうと思い立ちました。 (SymfonyWorld参加者はビデオを何度でもリプレイすることができるので、特典を利用して10回ぐらい基調講演を聞き返しました)

SymfonyUXとはなにか?

SymfonyのWebアプリケーションのビューにJavaScriptを組み込むことができる仕組みです。 「SymfonyForm, TwigのサーバーサイドレンダリングのDX(デベロッパー体験)を損なわずに、ネイティブアプリのような体験を統合」できるのを目指して作られています。

SymfonyUXで何ができるか?

SymfonyUXを使ってみたプロジェクトをこちらに用意しました。 https://github.com/77web/symfony-ux-example

composer require してSymfonyUXのコンポーネントを取り込むと、Flexがpackage.jsonを書き換え、SymfonyUXのJavaScriptを必要な依存としてフロントエンドに認識させます。 この状態で yarn install すると、EncoreがSymfonyUXのJavaScriptを含めた状態でwebpackでビルドします。 あとは、所定のtwig関数を書き込むだけで、フロントエンドの部品が組み込まれます。

つまり、composer requireしてPHPとtwigのコードを書くだけで、SymfonyUXのJavaScriptを利用したフロントエンド部品が利用できるのです。

SymfonyUXはどういう仕組みで動いているか?

SymfonyUXはStimulusというJavaScriptフレームワークを利用して作られています。 https://stimulusjs.org/
StimulusはもともとRuby On Railsと連携することを念頭に作られたフロントエンドフレームワークで、 Router for nodes DOMノードへのルーティングだけを提供するものということでした。(AngularのようなMVVMではないですね)

SymfonyUXが提供するのは、所定のHTMLを吐き出すTwigの関数
https://github.com/77web/symfony-ux-example/blob/main/templates/chart/index.html.twig#L6
と、それに合わせたJavaScriptファイルです。JavaScriptファイルは、Encoreを通じてWebpackでビルドされたものを読み込むことができます。
https://github.com/77web/symfony-ux-example/blob/main/templates/chart/index.html.twig#L10

※ SymfonyUXはStimulusを通じて各フロントエンドフレームワークとも連携できるそうです。(私のフロントエンド力が低すぎてサンプル作れませんでした…)

なぜSymfonyUXがつくられたのか?

昔、symfony1の頃にはprototype.jsと連携する機能がありましたが、Symfony2〜Symfony4の時代は、asseticやEncoreはあったものの、フロントエンドと連携する機能はコアとしては提供されていませんでした。サードパーティのバンドルという形で連携を試みた開発者もいますし、フロントエンドのコードはSymfonyアプリケーションに含めずにSPAなフロントエンドをまるでモバイルアプリのように独立させたものとAPIだけを通じて連携する道を取った開発者もいました。(カルテット開発部は途中まで前者で、ここ1年半ほどは後者でした) Fabien曰く、Symfony2の時代(約10年前)から今まで、フロントエンドはAngular, React, Vueのような人気のあるフレームワークが複数あって、どれと連携するか決めきれない状態だったから、ということです。

さて、Symfonyは HttpKernelInterface に10年間更新がないのが自慢だそうです(Fabien談)。 なぜ10年間更新無しで良いのかを考えたとき、

  • 標準
  • シンプル

という特徴があるから、ということが導き出されました。
そこから、Symfonyにフロントエンド統合の機能をつけるために必要な要素として下記が出てきます。

  • フロントエンドのコードも同じプロジェクト(レポジトリ)の中で管理したい
  • できるだけ複雑なことをせずに、ユーザー体験を向上させたい
    • しかしコード量は少なくしたい
  • 他の開発者のコードを再利用したい
  • 標準に寄せる、標準(ブラウザのhistory, url, クッキー, セッション)を再発明しない
  • 特定のフロントエンドフレームワークに依存しない
  • 自動テストしやすさを損なわない

これらを実現する方法として、Stimulusを使って、ピュアな(Vanilla)JavaScriptのライブラリと連携する機能を提供することにしたそうです。

感想

ずっと以前、symfony1の頃に、prototype.jsと連携するビューのファンクション( https://symfony.com/legacy/doc/book/1_0/en/11-Ajax-Integration )を使っていたことを懐かしく思い出しました(Symfonyユーザー会の割と古いメンバーでも実際にこれを使ったことがある人は少ない気がします :grin:

SymfonyUXは、フロントエンドとバックエンドを分離して開発するのが当たり前の理想的なプロジェクトにいる方から見れば、古臭く、わざわざフロントエンドとバックエンドを密結合にしようとする時代遅れな試みに見えるかもしれません。 しかし、12月のPHPカンファレンスで私がSPAのAPIについて発表した際に、「最近ではフロントエンドとPHPは別の人・チームで開発するようになっています」と言ったら、「まだフロントエンドもPHPも同じ人が書いてます」というコメントが多数あり、意外と両者を分離しきれずに開発しているプロジェクトは多いようです。幸いにもカルテットにはフロントエンドチームがいて、協力しあってSPAで開発することができます! :v: そのようなプロジェクトで苦労しているPHPのエンジニアにとっては、SymfonyUXは十分に助けになるのではないでしょうか。(日本に限らず、Symfony WorldでSymfonyUXが発表されたその場に参加していた海外のPHP開発者からも歓迎のコメントが多数あったことから、意外とここで苦労しているPHPエンジニアは多いのかもしれません)