1. kkeethのエンジニア雑談チャンネル
  2. No.122 朝活「リリースから5年..
2022-10-30 16:46

No.122 朝活「リリースから5年、Web フロントエンドの経年劣化と向き合う」をダラダラ読む回

はい.第122回は


リリースから5年、Web フロントエンドの経年劣化と向き合う
https://speakerdeck.com/keiya01/ririsukara5nian-webhurontoendonojing-nian-lie-hua-toxiang-kihe-u


の前半を読みました💁

どんな記事もそうですが,実際の知見や経験のお話は本当参考と学びになるのでとてもありがたいですね〜🙏今回もまさにそれで,知見の塊のような記事でした.自分が経験したことのないアーキテクチャでもあり,今後のプロジェクトの構成の一つの実績としてインプットさせていただきます!


ではでは(=゚ω゚)ノ


  • AmebaNews
  • SPA
  • MPA
  • AMP
  • React
  • React Router
  • Redux
  • CDN(Fastly)
  • SSR
  • @_keiya01
  • express
  • A/B Testing
  • リファクタリング
  • renderHTML


See Privacy Policy at https://art19.com/privacy and California Privacy Notice at https://art19.com/privacy#do-not-sell-my-info.

00:03
はい、10月25日火曜日ですね。遅刻は朝9時を回りました。今日また急にまた冷めま、冷めた?気温が下がりましたね。
昨日まだちょっと暖かかったんですけど、いきなり今日まだ冷えてきたので、まあ体調を気をつけていきたいなと思います。はい、ではおはようございます。
ひめみのkeeth、桑原です。では本日も朝活を始めていきたいと思います。前回前々回全然と、この4回分ですかね、ひたすらリアクトの話ですね。
特にユーザーRFCの記事ですね、fukioさんの記事2本と、RFC本体ですね、のプルリクエストを2回にわたって読んできました。
で、今日はまたちょっとフロントエンドの話に続くんですけど、タイトルのある通り、アベマのですね、ムディウェーブシャープさんという勉強会で、
ピーラブルナイトカンファレンス、今年の12月3日に行われるカンファレンス2022の、確か基調講演でも話されるような記憶がありますね。
間違ってなければ。アベマニュースとは、アベマニュースではちょっと、ちょっと新しい日常をコンセプトに芸能人有名人のエンタメニュースというのを中心にお届けしています。
中でもアベマブログとかアメブロ発の記事だったり特集などを豊富に揃えて画像や動画と合わせて提供しているというようなサービスだそうですね。
はい、アベマニュースでした。で、ウェブシステム概要です。デスクトップの方はJavaがベースで上にリアクトが乗っかってフロントを出していると。
で、バックエンドですね。モバイルですね。モバイルもJavaが乗っかってて、その上にAMPですね。AMPでやってるんだ。
もうやったことないのでAMP気になってたんですよね。というのが2017年のシステム概要でした。ざっくりとした。
で、デスクトップの話です。MPAとSPAが合わさった、いわばアイソモフィックウェブアップというところですね。
大部分のアーキテクチャはアメバブログというのを流用していますと。で、リアクト、リアクトルーター、リラックスという、一昔前のリアクトのデファクトみたいな構成ですね。
悪くはないんですけど、やっぱりクライアント処理がほぼないアベマニュースの構成としてはやっぱりやや過剰だと。それはそうかもしれないですね。
クライアント処理がほぼないんだったら、もうほぼ静的なふうにぺって見せるほうがいいので、そんなガッツリステート管理とかルーターまでガッツリやるとかなくてもMPAでもいい気がするんですけどね、そこまでいくんだったら。
実行時のその考慮も多く移行もしにくいと。そりゃそうですよね。SPAでガッツリやると複雑度が増したり、ライブラリーが上がれば突っ込むほどいろんなものを考慮しなきゃいけなくなるので、それはそうですよねって感じでした。
MPAプラスCDNですね。あのオワイルの方はMPAプラスCDNファストリを使っているとですね。やっぱファストリ使っているのはやっぱり早いんだろうなという印象はありますけどね。
で、AMPをフレームワークとして駆使しています。一応レスポンシブ対応もやっているというそうですね。
ただ、AMPのアンプですね。アンプってちゃんと言います。の利点もなくなってきたらしく、実装時にデスクトップのモバイルの構成の違いが大きすぎて、要は2つのアプリケーションをメンテナンスするような感じですね。これそうすると。
そこはちょっと辛いなという話だそうです。で、システム概要その先ですね。デスクトップのモバイルのところをやっぱり統合していきたいと。同じようなアーキテクチャでやりたいよねっていうような話が出てきましたと。
で、システム方針の変更だというところで、デスクトップのモバイルのアメバ的に良いところを保ったままやっぱり統合していこうと。リアクトとやっぱりMPAプラス入れるというところでやっていきたいなということですね。
03:02
で、刷新ですね。作り直しというのは今回除外するそうです。サービス規模的に少し整えるだけで意外と目的が達成できるんじゃないかなというふうに思ってたそうです。
で、システム構成が軽くなるので次の移行も選択肢も増えるはずという先のことも考えて良い設計じゃないかというところでした。
で、同時に開発環境、テストも含めの改善も行っていきたいというところですね。今後の機能追加であったり次のプチ刷新でも役立つようにしたいなということですね。
で、システム的2021年やりたいことリスト、Sharp268っていうGitHubの一周が立ち上がってて、わーっとチェックリストが載ってますね。
レスポンシブ、AMP配信の終了、TS化とかテスト通知だったりですね。VRT、UIテスト、単体テストの環境だったりとか、ストーリーブック、夜暗化、内部記事のCMS完全移行などなどみたいな結構テクニカルなところですね。
あと開発環境レベル、エンジニアレベルでの細かい対応とかもやっていきたいというところですね。
変更前の技術構成がそういうことですね。変更前の技術構成として一つ目がまずリアクトとエクスプレスを使ってSSRを実現している。
Nextとか使ってなくてガリガリにサーバーサイドレンダリングというのを実現していると。
ルーティングはリアクトルーダーを使っています。デストワーの管理はやっぱりReduxを使っています。5年前でこのスタックはかなり攻めていたので、確かに今聞くとおーって思いますよね。
ある種独自のNext.jsをやってたっていうことですね。NextあるんだったらNextに乗っかった方が今だといいんじゃないかと思いますけどね。
どのようにMPA化するかというのがセクション2ですね。5年前だから仕方ないかもしれないし決定するとしたら。でもかなり攻めたなと思いますね。
MPA化の方法です。ページ遷移をMPA的に遷移できるようにすれば良いと。リアクトルーターのリンクをAタグに置き換えるだけでいこうと。
まずはできるだけ少ない変更で様子を見てみたいよというお話でした。とにかくスモールスタートでそういうドラスティック変更に近いところをやるんだったら、ちょっとずつやっていくのがやっぱりいいかもしれないですね。
すでに運用しているサービスでもありますからね。で、そのサービスの影響を確認するというところです。
FastlyでABテスティング環境を作って、SPAとMPAでサービスへの影響もちょっと確認をしてみました。
FastlyのABテスティングはチュートリアルがあるのでとても簡単だと。そうなんですね。Fastly自体がそのABテスティングっていうチュートリアルを用意しているんですね。
ありがたいですね。Fastlyさん実は使ったことなかったんですけど、ちょっとこれは気になりますね。
また触りたい技術が増えていって、ちょっと今年のマストがどんどん増えていってどうしようって感じですけど、ちょっと優先度を決めます。
PVなのに影響がないことが確認できたら、徐々にMPAの影響範囲というのはちょっと広げていこうと。
データ数と平均と中央値をとっているってところですけど、リラックス外しがスパッといけるんであればいいんですけど、なんか落としはなりそうな気はしますけどね。
テストを後押しして品質を担保するところもやりたいと。で監視などを通してエラーが起きたときにすぐに対応できるようにしておく。
通知レベルの話ですね。次のリリースの時にもしかしたら考慮されるかもしれないですね。まあいいや。とりあえずリアクトの話ですね。
06:01
で続いてなぜリアクトルーターを外すのかですね。やっぱりMPAになるので。リアクトをどうするかを考えるっていうイシューですね。
があってそこでスペシフィケーションで、アメバニュースウェブのリアクトルーターがV3なのでどうにかしたいと。
ドキュメントもまともなのかないので、まあ何をすればやっぱり不安だと。しかも不便ですと。セキュリティ的な懸念もあるよというところがスペシフィケーションですと。
でやっぱりディベロップメントノーツってところでリアクトルーターをどうするかというのは以下の選択肢があると思いますと。
リアクトルーターを頑張って最新に上げる。違うライブラリを探してそっちを使う。自前でルーターを作る。リアクトごと剥がして単純なリンクで動く真のMPAにすると。
リアクトごと剥がすはちょっとあれかもしれないですけどね。4は現実的ではないので1か2または3になると思います。まあそりゃそうでしょうけど。
最終的にもはや自前の方が楽という結論。まあMPAだしというところだそうですね。
で次でなぜREDUXを外すのかですけども、昨今の流れとして責務を明確にした上でステータを管理する流れっていうのがあるし、そっちの方がやっぱりわかりやすいよねってことですね。
でMPAなのでストアにしてデータを貯めておくメリットはやっぱないよと。まあそうだよね。毎回毎回フラッシュするし、そこでちゃんとデータ取ってくるんで。
フロント側でデータ持たずに取ってきて出せば良くないは確かにあるかもしれないですね。
今回はグローバルで管理するデータが数量ほどしかないので、ストアはREACT.CONTEXTで管理をすると。
でMPAなのでREACT.QUERYなども使わずフェッチをFUXでラップしたものを使って特にクライアントでデータキャッシュはしないようにしようと。
まあでもファストリで使うからコンテンツそのものはキャッシュ化はすると思いますけど、アプリの方でのっていうところはしないということですね。
まあいいと思います。で進め方としては5段階にあって、1つ目にテストや監視周りの準備をして、2つ目にサーバー側のREACTルーターをエクスプレスベースに置き換えると。
3つ目にサーバー側のREDUXを外して、4番目にクライアント側のREDUXを外して、最後にクライアント側のREACTルーターも外して作成というところですね。
基本方針としては進めていくにあたって次の方針を意識した後、できるだけインターフェースを変えない、テンプレートを使ってできるだけロジックを考えずに置き換えができる状態を作る。
他の施策もあるので既存のコードと新規のコードを共存させつつ徐々に置き換えていく。既存の部分を外しやすいように新規のコードを追加していくと。
で、テストや監視周りの準備というところですね。
1つ目ですけど、イニシャルステートの変更をテストするためにスナップショートテストを行いますと。
意図せずにSSRの内容が変わるのはやっぱり防ぎたいと。
パペティアでHTMLに埋め込まれたステートを取得して、JSONとして保存しておき、変更後に比較をするというようなスナップショートテストをやったところですね。
これについては別の記事、参考記事のリンクが貼られてますよと。
ストーリーブックの使っているスナップショートテストではなくて、パペティアでやった感じなんですね。
別にどっちでも構わないと思いますけど。
ファストリーのABテスティングを次に使って、リラックスありなしのリアクトルーターのありなしのケースを作成して影響がないことを確認しつつ変更記事を適用していくというところですね。
あとデータドックとセントリーにABテストの、ABのケースのメトリクスを送って、それぞれで変化がないことを確認しようと。
データドックも使われてるんですけどね。
データドック、僕があまり使ったことないですけど、お金高そうという印象がやっぱりどうしても強くてですね。
これはリソースの話が出てくるので、さすがやなということですね。
09:00
セントリーはやっぱり本当にいろんな会社さん、大きい企業さん全然使われてるんですね、やっぱり。
いやーすごいな。
はいはい。
その辺を使って、メトリクスを送って変化ないことを確認した。
ちゃんと数字で見たよということですね。
続いて、そもそもSSRの仕組みですね。
それぞれのページでフェッチなどを通してデータを取得しますと。
アップコンポーネントに取得したデータを渡します。
サーバー側でリアクトのアップコンポーネント、一番親のコンポーネントですね。
これをHTMLの文字列に変換をしますと。
この時にアップコンポーネントでは、ページ、過去パスに応じたコンポーネントをルーティングする、リアクトルーターなどの役割ですね。
HTMLに変換する際に、SSRで使用したデータをwindow.initialstateなどに入れておいて、ハイドレーションできるようにしておくと。
はー、もう最後はウィンドウにガンとぶち込んでおくんですね、とりあえずね。
最後、ハイドレーションの際にSSR時のコンポーネントとクライアントが一致するように、クライアントでもやっぱりルーティングを行いますよというところですね。
で、サーバー側のリアクトルーターをエクスプレスベースに置き換えるという話ですけど、
既存のものとは別に新しくレンダーHTMLという共通の関数を定義して、この関数にイニシャルプロックスを渡すとSSRされて、
SSRしない場合は何も渡さないでOKみたいな仕組みにしたと。
分かりやすいですね、なるほど。
レンダーHTMLっていうところですね。
続いて、ページズルーティーズをエントリーポイントで、app.use()ページズルーティーズメソッドのように呼び出してルーティングをすると。
エクスプレスですからね、app.useでその中に入れると。
isgoodbyreduxの場合、
isgoodbyreduxっていうフラグが変数として定義されてますね。
名前にセンスがあってちょっと僕笑っちゃいました。
isgoodbyreduxの場合、以降のパスにはマッチしないので既存のコードに変更を加えることなく新しく書き換えることができる。
書き加えることもできるってことですね。
isgoodbyreduxの場合、ではない場合はreturnでnextのルーターを渡してあげるという感じですね。
で、サーバー側のredux外しのお話ですけど、reduxconnectというライブラリを通してSSRをしていたと。
そんなのがあったんですね。
で、サーバー側のルーティングに合わせて新規ページを作ってreduxactionと同じフェッチ処理を呼び出しますと。
で、フェッチしたデータをコンポーネントのプロプスに合わせて渡してあげようと。
さっきの方針に書かれたんですね。
で、新規ページのSSR部分ですね、これは。
今ソースコード出てます。before、afterがあるんですけど、ちょっと小さいし、口頭で説明するとあれなので、
今回は割愛します。みなさんもちょっとまた見てみてください。
一応レンダーHTMLにインシャルプロプスを渡しているというところだけ、先ほど言ったことを実現したよということですね。
ちょっとコードの量は長くなった感がありますね。
まあ、開業も入っているからかもしれないですけどね。
まあ、細かく細かくなったというのがいいかもしれないです。
で、厳密に言うとレンダーHTMLのところに引数はリクエストとレスポンスと、最後にオブジェクトとして、
インシャルプロプスと適当なやつというのを入れている感じですね。
で、クライアント側のリラックス外しのところです。
usefetchのようなフェッチ用のフックスを作りますと。
で、classコンポーネントをfunctionコンポーネントに置き換えます。
あー、そもそもやっぱclassコンポーネントだったんですね。
で、abテストのためにリラックスのコードを残しつつ、新規のコードをどんどん書き足していきましょうと。
はい、言ってますね。なるほど、なるほど。
12:02
で、クライアント側のリラックス外しで、ついでにこれソースコードが出てますね。
ベースとなるusefetchの内部でabテスティングの判定をしています。
各API用のフックスというのはusefetchを経由してAPIにアクセスをしていますと。
usefetchって、ユーザーの型のフックを作って、その中でフェッチを使っているってことですね。
ジェネリクスでデータのエクステンズでunknownをエクステンズしています。
で、引数にフェッチっていうのが第一引数の関数で、もちろんこれはレスポンスはプロミスデータがあります。
で、もう一個フェッチもはっていうのはオプショナルですね。
フェッチもはみたいな型があって、データはジェネリクスで渡されるという感じですね。
で、const isgoodbyredaxっていうのがここで定義されるんですね。
usefetch内でisgoodbyredaxっていうのが定義されていて、
で、中はですね、process.envでnodeenvを見て、
デベロップメントだったら、もしくはgetnewstestingvalueですね。
getnewstestingvalueっていうメソッドがあって、
abtesting.mapのgoodbyredaxっていうのがtrueであるんだったら、
isgoodbyredaxがtrueだということですね。このフラグが立ちます。
なので、isgoodbyredaxっていうのがreturn undefinedになってということですね。
で、最後にusefetchinnerっていうのをreturnしてあげるということですね。
はい。ちょっと口頭だったので、ソースコード読んでもふーんってなるかも皆さんは知らないですけどね。ごめんなさい。
で、続いてクライアント化のredax外しですね。
えーと、続いて、改善前はclass.componentで書かれていたんですけど、
これをatomicdesignorganismsでfetchしていたんですね、今は。
どうしても同一コンポーネントに修正加える必要があったようなところですね。
で、コンテナー層など1枚挟んであればもう少し書き換えやすかったかもしれないですけど、
これは教訓だったところですね。
で、beforeafterがあって、classから関数コンポーネントにちゃんと置き換えましたようなところですね。
で、useeffectを使ったりとかなんちゃらしたりとかっていうので、見やすいですね。やっぱりコードスパッときれいになっていくので。
で、organismsでfetchしていたってのはやっぱりそれはあんまりよろしくないですね。
なるべくなるべくfetchするところっていうのは1箇所でとどめたいですけど、
大きいとこまでいってからfetchするかどうかっていう話はあったりしますけどね。
ただいってatmosレベルでやるかっていうのはそんなわけはもちろんないですからね。
コンテナー層など1枚挟ればっていうのはそうですね。
1個独自の層を挟んでそこでfetchをするっていうので共通ルール作っておくといいかもしれないです。
続いてクライアント側のreact-router外しです。
react-routerのversion3をやっぱり最新に上げるのは辛かったと。
universal-router-likeなシンプルな独自ルーターを今回作ったんですよ結局ね。
ssr時とhydration時にルーティングを走らせてこれを各ページごとに適用していくよと。
universal-router-likeなルーターの定義ってことですけど、
とりあえずマッチしたコンポーネントを回数にしようと。
コードスプリッティングは未対応ですと。
そこまで実装すると結構大変ですよね。
universal-routesっていうのを定義しておいて、
find-component-from-routesみたいなのを関数で作って、
そこをマッチしているかどうかというので返すような関数を作ったという感じですね。
割とシンプルですねこれでもいうて。
パスでとりあえず取ってきてそこからマッチングさせるような感じになる。
厳密にマッチさせるような処理をさせる関数自体の引数は、
パスネームで文字列渡してルーティー図でuniversal-routesの配列を渡してあげる。
15:02
最後にabtestのコードを外しましょうってことですね。
1ヶ月ほど要素を見た後に一気に外していきました。
バンドルサイズが合計で59.66kB、gzipで減りましたと。
gzipで59.66kB減ったはデカいですね。
リアクトルーターがそもそも33.94kBで、
リラックスが25.73kBあるので、
足し合わせて59.66kBですね。
いやバンドルサイズこんなガツンと減るって。
やっぱりリアクトルーターとリラックスって大きいんですね。
ではセクション4まとめです。
リアクトルーターv3のドキュメントがないのはやっぱ辛かったと。
リアクトのSSR周りの影響度を再理解する良い機械だったということですね。
リアクトルーター周りも深く知ることができて、
勉強になりましたよってことだそうです。
今のが一人目の方で、続いてデベロッパーエクスペリエンスの改善、
高見俊介さんという方のお話に続くそうですね。
今のはモバイルとデスクトップを一元、
同じようなアーキテクチャで統合していくっていう話だった。
続いてはデベロッパーエクスペリエンスの改善の話に移るそうです。
この話してもいいんですけどちょうど区切りもいいのと、
時間も26分で近づいてきたのでちょっと短いですけど、
今日ここで区切って明日はこの続きからでやっていって、
残り余った時間は別の記事読むという風にした方が良さそうな気がするので、
すいませんが今日はちょっとここで区切りたいと思います。
まさかこのスライドが2人で登壇されていて、
一人目二人目で区切られているとちょっと僕は思ってなかったので、
今日はここで区切らせていただきたいと思います。
また明日も緩く読んでいきますので興味のある方はご参考いただければと思います。
明日も緩くやりますので非常に勉強できたらなと思います。
では火曜日ですね。今週も2日目ですけど頑張っていけたらなと思います。
それでは終了します。お疲れ様でした。
16:46

コメント

スクロール