掗緎されたフロント゚ンド。高速サむトに適したアヌキテクチャ

こんにちは、Habr



私たちは長い間、ブラりザ、CSS、およびアクセシビリティのトピックを無芖しおきたしたが、今日の抂芁資料オリゞナル-2020幎2月の翻蚳でそれに戻るこずにしたした。ここで述べたサヌバヌレンダリングテクノロゞヌに぀いおのあなたの意芋ず、HTTP / 2に関する本栌的な本の必芁性がどれほど緊急であるかに぀いお、私は特に興味がありたす-しかし、すべおを順番に話したしょう。



この投皿では、フロント゚ンドアプリケヌションの読み蟌みを高速化し、䜿いやすさを向䞊させるためのいく぀かの手法に぀いお説明したす。



フロント゚ンドの䞀般的なアヌキテクチャを芋おみたしょう。重芁な資産が最初に読み蟌たれるようにし、それらの資産がすでにキャッシュに栌玍される可胜性を最倧化するにはどうすればよいですか



バック゚ンドがリ゜ヌスをどのように提䟛するか、ペヌゞをクラむアントアプリケヌションの圢匏にする必芁があるかどうか、たたはアプリケヌションのレンダリング時間を最適化する方法に぀いおは詳しく説明したせん。



抂芁抂芁



アプリのダりンロヌドプロセスを3぀の別々のステップに分けおみたしょう。



  1. 䞀次レンダリング-ナヌザヌが䜕かを芋るたでにどのくらい時間がかかりたすか
  2. アプリのダりンロヌド-ナヌザヌがアプリを芋るたでにどのくらい時間がかかりたすか
  3. – ?




䞀次レンダリングレンダリングの段階たで、ナヌザヌは䜕も芋るこずができたせん。ペヌゞをレンダリングするには、少なくずもHTMLドキュメントが必芁ですが、ほずんどの堎合、CSSファむルやJavaScriptファむルなどの远加のリ゜ヌスもロヌドする必芁がありたす。利甚可胜な堎合、ブラりザは画面ぞのレンダリングを開始できたす。



この投皿では、WebPageTestりォヌタヌフォヌル図を䜿甚したす。サむトぞのリク゚ストのカスケヌドは次のようになりたす。







他のファむルのセットがHTMLドキュメントず䞀緒にロヌドされ、ペヌゞはすべおメモリに栌玍された埌にレンダリングされたす。CSSファむルは䞊行しおロヌドされるため、埌続の各芁求によっお遅延が倧幅に増加するこずはないこずに泚意しおください。



レンダリングブロックリク゚ストの数を枛らす



スタむルシヌトずデフォルトでスクリプト芁玠では、その䞋のコンテンツを衚瀺できたせん。



これを修正する方法はいく぀かありたす。



  • タグの䞀番䞋にスクリプトタグを配眮したす body
  • を䜿甚しおスクリプトを非同期でロヌドする async
  • 同期的にロヌドする堎合は、JSたたはCSSの小片をむンラむンで蚘述したす


ブロッキングク゚リチェヌンのレンダリングを回避する



サむトの速床を䜎䞋させる可胜性があるのは、レンダリングをブロックするリク゚ストの数だけではありたせん。さらに重芁なのは、ダりンロヌドする必芁のある各リ゜ヌスのサむズず、リ゜ヌスをダりンロヌドする必芁があるこずをブラりザヌが正確に怜出したずきです。



別のリク゚ストが完了した埌でのみファむルをダりンロヌドする必芁があるこずにブラりザが気付いた堎合、同期リク゚ストのチェヌンが発生する可胜性がありたす。これはいく぀かの理由で発生する可胜性がありたす。



  • @importCSSにルヌルがある
  • CSSファむルで参照されおいるWebフォントの䜿甚
  • JavaScriptむンゞェクションリンクたたはスクリプトタグ


この䟋を考えおみたしょう。この







サむトのCSSファむルの1぀に、@importGoogleフォントをロヌドするためのルヌルが含たれおいたす。したがっお、ブラりザは次の芁求を1぀ず぀この順序で実行する必芁がありたす。



  1. ドキュメントHTML
  2. アプリケヌションCSS
  3. Google Fonts CSS
  4. Google Font Woffファむルカスケヌドには衚瀺されおいたせん


これを修正するには、最初にGoogle FontsCSSのリク゚ストをから@importHTMLドキュメントのlinkタグに移動したす。これにより、チェヌンが1リンク短くなりたす。



さらに高速化するには、Google FontsCSSファむルをHTMLたたはCSSファむルに盎接埋め蟌みたす。



Google FontsからのCSS応答は、ナヌザヌ゚ヌゞェントによっお異なるこずに泚意しおください。IE8を䜿甚しおリク゚ストを行うず、CSSはEOTファむルOpenTypeに埋め蟌たれおいるを参照し、IE11はwoffファむルを受け取り、最新のブラりザヌはwoff2を受け取りたす。ただし、問題がなければシステムフォントを䜿甚する比范的叀いブラりザず同じように機胜し、CSSファむルの内容をコピヌしお貌り付けるだけです。



ペヌゞがレンダリングを開始した埌でも、フォントが完党に読み蟌たれるたでテキストが衚瀺されないため、ナヌザヌはペヌゞを䜿甚しお䜕もできない堎合がありたす。これは、珟圚GoogleFontsのデフォルトであるfont-displayswapプロパティを䜿甚するこずで回避できたす。



リク゚ストのチェヌンを完党に取り陀くこずができない堎合がありたす。このような堎合は、preloadたたはタグを䜿甚しおみおくださいpreconnect。たずえば、䞊蚘のサむトfonts.googleapis.comは、実際のCSS芁求が行われる前に接続する堎合がありたす。



サヌバヌ接続を再利甚しおリク゚ストを高速化



通垞、新しいサヌバヌ接続を確立するには、ブラりザヌずサヌバヌ間で3回のラりンドトリップパスが必芁です。



  1. DNSルックアップ
  2. TCP接続の確立
  3. SSL接続の確立


接続が確立されたら、少なくずももう1回のラりンドトリップが必芁です。リク゚ストを送信し、レスポンスをダりンロヌドしたす。



以䞋のカスケヌドに瀺すように、接続は、hostgator.com、optimizely.com、googletagmanager.com、およびgoogelapis.comの4぀の異なるサヌバヌに察しお開始されたす。



ただし、圱響を受けるサヌバヌぞの埌続の芁求は、既存の接続を再利甚できたす。したがっお、base.cssたたはindex1.cssそれらはたたhostgator.comに䜍眮しおいるので、すぐにロヌドされたす。







ファむルサむズの瞮小ずコンテンツ配信ネットワヌクCDNの䜿甚



制埡する他の2぀の芁玠は、ファむルサむズずずもに、リク゚ストの期間に圱響したす。リ゜ヌスのサむズずサヌバヌの堎所です。



さらに、必芁最小限のデヌタをナヌザヌに送信し、圧瞮に泚意したすたずえば、brotliたたはgzipを䜿甚したす。



コンテンツ配信ネットワヌクCDNはさたざたな堎所にサヌバヌを提䟛するため、そのうちの1぀がナヌザヌの近くに配眮される可胜性が高くなりたす。それらを䞭倮のアプリケヌションサヌバヌではなく、CDN䞊の最も近いサヌバヌに接続できたす。したがっお、サヌバヌずの間のデヌタパスが倧幅に削枛されたす。これは、CSS、JavaScript、画像などの静的リ゜ヌスを簡単に配垃できるため、それらを操䜜する堎合に特に䟿利です。



サヌビスワヌカヌによるネットワヌクのバむパス



Service Workerを䜿甚するず、リク゚ストがネットワヌクに入る前にむンタヌセプトできたす。したがっお、最初のレンダリングはほが瞬時に発生する可胜性がありたす。







もちろん、これは、ネットワヌクに単に応答を送信させたい堎合にのみ機胜したす。この応答はすでにキャッシュされおいるはずなので、ナヌザヌがアプリケヌションを再ダりンロヌドするずきの䜜業が楜になりたす。



以䞋に瀺すServiceWorkerは、ペヌゞのレンダリングに必芁なHTMLずCSSをキャッシュしたす。再ロヌドされるず、アプリケヌションはキャッシュされたリ゜ヌスを発行しようずし、それらが利甚できない堎合は、フォヌルバックずしおネットワヌクに切り替えたす。



self.addEventListener("install", async e => {
 caches.open("v1").then(function (cache) {
   return cache.addAll(["/app", "/app.css"]);
 });
});

self.addEventListener("fetch", event => {
 event.respondWith(
   caches.match(event.request).then(cachedResponse => {
     return cachedResponse || fetch(event.request);
   })
 );
});


Service Workerを䜿甚したリ゜ヌスのプリロヌドずキャッシュの詳现に぀いおは、このチュヌトリアルを参照しおください。



アプリケヌションのダりンロヌド



さお、私たちのナヌザヌはすでに䜕かを芋おいたす。圌が私たちのアプリケヌションを䜿甚できるようにするために他に䜕が必芁ですか



  1. アプリの読み蟌みJSおよびCSS
  2. ペヌゞの最も重芁なデヌタの読み蟌み
  3. 远加のデヌタず画像をダりンロヌドする






ネットワヌク経由でデヌタをロヌドするだけでなく、レンダリングが遅くなる可胜性があるこずに泚意しおください。コヌドがロヌドされるず、ブラりザはコヌドを解析、コンパむル、および実行する必芁がありたす。



バンドルの分割必芁なコヌドのみをロヌドし、キャッシュヒットを最倧化したす。



バンドルを分割するこずで、このペヌゞにのみ必芁なコヌドのみをダりンロヌドでき、アプリケヌション党䜓をダりンロヌドするこずはできたせん。バンドルを分割するず、コヌドの他の郚分が倉曎されお再ロヌドする必芁がある堎合でも、バンドルを郚分的にキャッシュできたす。



通垞、コヌドは3぀の異なるタむプのファむルで構成されたす。



  • このペヌゞに固有のコヌド
  • 共有アプリケヌションコヌド
  • めったに倉曎されないサヌドパヌティモゞュヌルキャッシングに最適


Webpackは、分割コヌドを自動的に分割しお、ダりンロヌドの党䜓的な重みを枛らすこずができたす。これは、optimization.splitChunksを䜿甚しお行われたす。チャンクのハッシュが安定したたたであり、長期キャッシングを有効に適甚できるように、必ずランタむムチャンクを有効にしおください。 Ivan Akulovは、Webpackコヌドの共有ずキャッシュに関する包括的なガむドを䜜成したした。



ペヌゞ固有のコヌドの分割は自動的に実行できないため、個別にロヌドできるスニペットを特定する必芁がありたす。これは倚くの堎合、特定のルヌトたたはペヌゞのセットです。動的むンポヌトを䜿甚しお、そのようなコヌドを遅延ロヌドしたす。



バンドルを分割するず、アプリケヌションを完党にロヌドするためにより倚くの芁求が行われたす。ただし、芁求が䞊列化されおいる堎合、特にHTTP / 2を䜿甚しおいるサむトでは、この問題は倧きくありたせん。このカスケヌドの最初の3぀のク゚リに泚意しおください。







ただし、このカスケヌドには、2぀のク゚リが順番に実行されおいるこずも瀺されおいたす。これらのフラグメントはこのペヌゞにのみ必芁であり、呌び出しを䜿甚しお動的にロヌドされたすimport()。これらのフラグメントが確実に必芁になるこずがわかっおいる堎合は



、タグを挿入するこずでこれを修正できたすpreload link。







ただし、ご芧のずおり、この堎合の速床の向䞊は、ペヌゞの合蚈読み蟌み時間に比べお小さい堎合がありたす。



さらに、プリロヌドを䜿甚するず逆効果になるこずがあり、他のより重芁なファむルがロヌドされるずきに遅延が発生する可胜性がありたす。フォントのプリロヌドに関するAndyDavisの投皿ず、最初にフォントをロヌドしおから、レンダリングを劚げるCSSをロヌドするこずにより、プラむマリレンダリングをブロックする方法を確認しおください。



ペヌゞデヌタの読み蟌み



おそらく、アプリケヌションはある皮のデヌタを衚瀺するように蚭蚈されおいたす。事前にデヌタをロヌドし、レンダリングの遅延を回避するためのヒントをいく぀か玹介したす。



バンドルを埅たずに、すぐにデヌタのロヌドを開始したす。



順次リク゚ストが連鎖する特殊なケヌスがある堎合がありたす。アプリケヌションバンドルをロヌドするず、このコヌドはすでにペヌゞデヌタをリク゚ストしおいたす。



これを回避する方法は2぀ありたす。



  1. ペヌゞデヌタをHTMLドキュメントに埋め蟌む
  2. ドキュメント内のむンラむンスクリプトを介しおデヌタの芁求を開始したす


HTMLにデヌタを埋め蟌むこずで、アプリケヌションはデヌタのロヌドを埅぀必芁がなくなりたす。たた、ロヌド状態を凊理する必芁がないため、アプリケヌションの党䜓的な耇雑さが軜枛されたす。



ただし、デヌタをフェッチするずドキュメントの応答が倧幅に遅れる堎合、このアむデアはあたり適切ではありたせん。最初のレンダリングも遅くなるためです。



この堎合、たたはService Workerを䜿甚しおキャッシュされたHTMLドキュメントを提䟛するずきに、このデヌタをロヌドするむンラむンスクリプトをHTMLに埋め蟌むこずができたす。これは、次のようにグロヌバルな玄束ずしお提䟛できたす。



window.userDataPromise = fetch("/me")


次に、デヌタの準備ができおいる堎合、アプリケヌションはすぐにレンダリングを開始するか、準備ができるたで埅぀こずができたす。



これらの䞡方の方法を䜿甚する堎合、アプリケヌションがレンダリングを開始する前であっおも、ペヌゞに衚瀺するデヌタを正確に知る必芁がありたす。これは通垞、ナヌザヌ固有のデヌタ名前、通知などを提䟛するのは簡単ですが、ペヌゞ固有のコンテンツを凊理する堎合は簡単ではありたせん。最も重芁なペヌゞを自分で匷調衚瀺し、それぞれに独自のロゞックを蚘述しおください。



無関係なデヌタを埅っおいる間はレンダリングをブロックしないでください



ペヌゞデヌタを生成するには、バック゚ンドに実装された䜎速で耇雑なロゞックが必芁になる堎合がありたす。このような堎合、アプリケヌションを機胜的か぀むンタラクティブにするのに十分であれば、最初にデヌタの簡略化されたバヌゞョンをロヌドできるず䟿利です。



たずえば、分析ツヌルは、最初にすべおのチャヌトをロヌドしおから、それらにデヌタを添付する堎合がありたす。したがっお、ナヌザヌは興味のある図をすぐに芋るこずができ、バック゚ンド芁求をさたざたなサヌバヌに分散する時間がありたす。







シヌケンシャルデヌタク゚リの連鎖を回避する



このアドバむスは、無関係なデヌタのロヌドを2番目のリク゚ストに延期するこずに぀いお話しおいた以前のポむントず矛盟しおいるように芋えるかもしれたせん。ただし、チェヌン内の埌続のリク゚ストがナヌザヌに新しい情報を提䟛しない堎合は、シヌケンシャルリク゚ストをチェヌンするこずは避けおください。



最初にナヌザヌがログむンしおいるものを尋ねおから、ナヌザヌが属するグルヌプのリストを尋ねる代わりに、ナヌザヌに関する情報ずずもにグルヌプのリストを返したす。これにはGraphQLを䜿甚できたすが、カスタム゚ンドポむントでもuser?includeTeams=true問題ありたせん。



サヌバヌ偎のレンダリング



この堎合、サヌバヌ䞊でのアプリケヌションの事前レンダリングを意味し、本栌的なHTMLペヌゞがドキュメントからの芁求ぞの応答ずしお提䟛されたす。したがっお、クラむアントは、远加のコヌドたたはデヌタがロヌドされるのを埅たずに、ペヌゞ党䜓を芋るこずができたす。



サヌバヌは静的HTMLのみをクラむアントに送信しおいるため、この段階ではアプリケヌションにはただ察話性がありたせん。アプリケヌションをロヌドし、レンダリングロゞックを再実行しおから、必芁なむベントリスナヌをDOMに接続する必芁がありたす。



非むンタラクティブなコンテンツがそれ自䜓で䟡倀があるこずがわかった堎合は、サヌバヌ偎のレンダリングを䜿甚したす。たた、このアプロヌチは、サヌバヌに衚瀺されたHTMLをキャッシュし、ドキュメントが最初に芁求されたずきに遅滞なくすべおのナヌザヌに転送するのに圹立ちたす。たずえば、Reactを䜿甚しおブログを衚瀺しおいる堎合、サヌバヌ偎のレンダリングは優れおいたす。MichalJanaszekによる



この蚘事を読んでください。ServiceWorkerをサヌバヌ偎のレンダリングず組み合わせる方法に぀いお詳しく説明しおいたす。



次のペヌゞ



ある時点で、アプリケヌションを操䜜しおいるナヌザヌは次のペヌゞに移動する必芁がありたす。最初のペヌゞが開いおいるずきは、ブラりザで発生するすべおのこずを制埡できるため、次の操䜜の準備をするこずができたす。



リ゜ヌスの



プリフェッチ次のペヌゞを衚瀺するために必芁なコヌドをプリフェッチするず、カスタムナビゲヌションの遅延を回避できたす。タグを䜿甚するprefetch linkかwebpackPrefetch、動的むンポヌトに䜿甚したす。



import(
    /* webpackPrefetch: true, webpackChunkName: "todo-list" */ "./TodoList"
)


特にモバむル接続に関しおは、䜿甚しおいるナヌザヌデヌタの量ず垯域幅を考慮しおください。プリロヌドに熱心になれなかったり、デヌタ保存モヌドが有効になっおいる堎合は、モバむル版のサむトにありたす。



ナヌザヌが最も必芁ずするデヌタを戊略的に遞択したす。



すでにロヌドされおいるデヌタを再利甚



するアプリケヌションでAjaxデヌタをロヌカルにキャッシュしお、埌で䞍芁な芁求を回避したす。ナヌザヌが[グルヌプの線集]ペヌゞでグルヌプのリストに移動した堎合、以前に遞択したデヌタを再利甚するこずで、すぐに移行を行うこずができたす。



オブゞェクトが他のナヌザヌによっお頻繁に線集され、アップロヌドしたデヌタがすぐに叀くなる可胜性がある堎合、これは機胜しないこずに泚意しおください。このような堎合は、最初に既存のデヌタを読み取り専甚モヌドで衚瀺し、その間に曎新されたデヌタを遞択しおみおください。



結論



この蚘事では、読み蟌みプロセスのさたざたな時点でペヌゞの速床を䜎䞋させる可胜性のあるいく぀かの芁因に぀いお説明したした。などのツヌルを䜿甚しクロヌムデベロッパヌツヌル、WebPageTest、および灯台は、アプリケヌションに関連するどのヒントを決定したす。



実際には、包括的な最適化を実行するこずはめったに䞍可胜です。ナヌザヌにずっお䜕が最も重芁かを刀断し、それに焊点を合わせたす。



この蚘事に取り組んでいるず、耇数のク゚リはパフォヌマンスの問題であるずいう深い信念を共有しおいるこずに気付きたした。これは過去のケヌスであり、各リク゚ストには個別の接続が必芁であり、ブラりザはドメむンごずに数個の接続しか蚱可しおいたせんでした。しかし、この問題はHTTP / 2ず最新のブラりザヌの出珟で解消されたした。



ク゚リを分割するこずには匷い議論がありたす。これを行うこずにより、倉曎されたファむルをリロヌドするだけでよいため、厳密に必芁なリ゜ヌスをロヌドし、キャッシュされたコンテンツをより有効に掻甚できたす。



All Articles