Η περίπτωση μερικής ενυδάτωσης (με Next και Preact)

Την άνοιξη, είμαστε υπεύθυνοι για τη διατήρηση διαφόρων διαφορετικών ειδησεογραφικών δικτυακών τόπων για τη μητρική εταιρεία μας Axel Springer. Μία από τις πιο πρόσφατες κυκλοφορίες μας, welt.de, είναι η γρηγορότερη δικτυακή πηγή ειδησεογραφικών μέσων στη Γερμανία. ένας από τους πιο επιδιωκόμενους στόχους μας είναι να επιτύχουμε συνεχώς την καλύτερη δυνατή απόδοση και ο λόγος για αυτό είναι απλός: η καλύτερη απόδοση συνήθως σημαίνει καλύτερη εμπειρία χρήστη και επομένως υψηλότερη διατήρηση του χρήστη.

tl, dr

Μετακινηθείτε με κύλιση προς τα κάτω στην επιλογή "Ανασκόπηση" για μια σύντομη περίληψη με μια ετικέτα πληροφοριών. Τα βασικά σημεία για αυτό με λίγα λόγια:
  • Η απόδοση είναι ζωτικής σημασίας για τον ιστό
  • για να επιτύχουμε υψηλή απόδοση θέλουμε να στείλουμε όσο το δυνατόν λιγότερο στον πελάτη
  • μπορούμε να το κάνουμε επιλέγοντας τα συστατικά που θέλουμε να στείλουμε και να ενυδατώσουμε στον πελάτη
  • αφήνουμε το υπόλοιπο της σελίδας στατικό και έχουμε πολλαπλές ρίζες απόδοσης
  • Όλα αυτά λειτουργούν με μια ενιαία βάση κώδικα
  • Ακολουθεί ένα μακρύ άρθρο σχετικά με τον τρόπο με τον οποίο υλοποιήσαμε τα παραπάνω βήματα. Θα βρείτε επίσης έναν σύνδεσμο για ένα WIP repo της εφαρμογής αυτής εδώ:
  • https://github.com/spring-media/next-super-performance

Απόδοση στον ιστό

Αν ακολουθήσετε τον Addy Osmani γνωρίζετε ήδη το τρυπάνι, γράφει πολλά για την αιτία και τα αποτελέσματα της απόδοσης στο διαδίκτυο. Για να ξεκινήσετε, μπορώ να συστήσω το άρθρο του Addy για το "Το κόστος της JavaScript το 2018". Δύο πολύ σημαντικά πράγματα που μπορείτε να μάθετε από αυτό το άρθρο είναι:

  • Το κόστος της JavaScript δεν είναι μόνο ο χρόνος που χρειάζεται για να φορτώσετε το πακέτο σας
  • Ο χρόνος για την ανάλυση και την εκτέλεση του JavaScript σας είναι εξίσου σημαντικός

Φυσικά, υπάρχει πολύ περισσότερη απόδοση από αυτήν, συμπεριλαμβανομένων των στρατηγικών φόρτωσης, μιας κρίσιμης διαδρομής rendering, προϋπολογισμών απόδοσης και ούτω καθεξής. Όλα αυτά τα πράγματα περιστρέφονται γύρω από το πώς να βελτιστοποιήσετε ό, τι καταλήγετε να στέλνετε στον πελάτη σας. Αυτό που θέλουμε να επικεντρωθούμε σε μερική ενυδάτωση δεν είναι ο τρόπος για να βελτιστοποιήσετε αυτό που στέλνετε, αλλά πόσο στείλετε καθόλου.

Μια βασική πτυχή αυτού θα είναι η απόδοση διακομιστή (SSR), επειδή υπάρχουν πολλά που μπορούμε να κάνουμε στο διακομιστή που δεν χρειάζεται να γίνει στον πελάτη. Στην πραγματικότητα, αυτή είναι η ουσία αυτού του άρθρου. Ό, τι μπορεί να γίνει στο διακομιστή θα πρέπει να γίνει στον εξυπηρετητή, αλλά ο πελάτης θα πρέπει να αποστέλλεται ό, τι πρέπει να εκτελεστεί στην πλευρά του πελάτη. Επιπλέον, μπορείτε ακόμα να εφαρμόσετε ό, τι γνωρίζετε σχετικά με την απόδοση του ιστού, αλλά θα έχετε πολύ λιγότερους παράγοντες για τη διαχείριση. Αυτό θα εξηγηθεί σε βάθος περαιτέρω στο άρθρο.

SSR και ενυδάτωση

Για την επίτευξη του στόχου μας για την οικοδόμηση μιας ιστοσελίδας με υψηλή απόδοση, θα χρησιμοποιήσουμε μια τροποποιημένη έκδοση του Next. Έπειτα έρχεται σε συνδυασμό με πολλά ενσωματωμένα χαρακτηριστικά βελτίωσης της απόδοσης, το πιο σημαντικό, το Next κάνει το server rendering side (SSR) έξω από το κουτί. Αυτό σημαίνει ότι το Επόμενο θα πάρει την εφαρμογή σας, γραμμένο σε React και με αυτή τη σειρά:

  1. Εκτελέστε το ως συμβολοσειρά HTML στο διακομιστή
  2. Στείλτε την αποδιδόμενη συμβολοσειρά HTML στους χρήστες σας ως πηγαίο κώδικα
  3. Στείλτε τον κωδικό σας React ως JavaScript στους χρήστες σας
  4. Και τελικά "ενυδατώστε" την HTML σας χρησιμοποιώντας τον κωδικό σας React

Για να "ενυδατωθεί" σε αυτή την περίπτωση σημαίνει ότι το Next θα αναπτύξει τον κώδικα του React μέσω της HTML σας και στη συνέχεια θα πει React κάτι παρόμοιο:

Hey React, εδώ είναι κάποια HTML που ταιριάζει ακριβώς με ό, τι θα κάνατε αν σας έλεγα να αποτυπωθεί σε έναν κενό κόμβο DOM, παρακαλώ μην επανακαταγράφετε τα πάντα, αντί να χρησιμοποιήσετε το HTML σαν να το δώσατε και να συνεχίσετε η μέρα σου

Η αντίδραση θα απαντήσει

Εντάξει, απλά σας κοίταξα HTML και φαίνεται ότι ταιριάζει ακριβώς με αυτό που θα έκανα. Είναι δροσερό. Θα επισυνάψω κάποιους χειριστές συμβάντων στο DOM σας και η σελίδα σας τώρα λειτουργεί ως εφαρμογή μιας σελίδας, όπως και εγώ ο ίδιος.

Τα οφέλη από τη φόρτωση ενός ιστότοπου με αυτόν τον τρόπο είναι απλά: Οι χρήστες σας θα βλέπουν ήδη μια πλήρως επεξεργασμένη σελίδα όταν φορτώνουν τον ιστότοπό σας (αντί για μια κενή σελίδα) και στη συνέχεια γίνεται διαδραστική. Ο ιστότοπός σας θα επωφεληθεί επίσης από μια σημαντική βελτίωση της απόδοσης, επειδή το πρόγραμμα περιήγησης δεν χρειάζεται να κάνει οποιεσδήποτε επαναλήψεις (επαναφορά της σελίδας σας με το React).

Πάρα πολλά έξοδα

Αυτή η προσέγγιση είναι φανταστική όταν θέλετε να δημιουργήσετε εφαρμογές ιστού ή με άλλα λόγια ιστοσελίδες που πρέπει να ελέγχονται πλήρως από το JavaScript και είναι επίσης διαδραστικές όπου κι αν κάνετε κλικ. Παραδείγματα αυτής της προσέγγισης στην παραγωγή περιλαμβάνουν ιστοσελίδες όπως το Facebook, το Twitter και οι ηλεκτρονικοί υπολογιστές ηλεκτρονικού ταχυδρομείου.

Αλλά οι περισσότεροι ιστότοποι δεν είναι έτσι, οι περισσότεροι ιστότοποι είναι ακίνητοι και περιέχουν επίσης κάποια διαδραστικά στοιχεία.

Τώρα καταλήγετε να στέλνετε ολόκληρο τον κώδικα αίτησής σας στους χρήστες σας, συμπεριλαμβανομένων των στοιχείων React για κάθε παραγράφου τίτλου ή κειμένου οπουδήποτε στη σελίδα σας. Το αποτέλεσμα είναι μια άσκοπα τεράστια δέσμη που πρέπει να φορτωθεί, να αναλυθεί και να εκτελεστεί. Αυτό οδηγεί σε υποβέλτιστη απόδοση, η σελίδα σας θα είναι αργή (er) ειδικά για τους χρήστες κινητών τηλεφώνων και για κανένα λόγο!

Και αυτό είναι χάλια.

Λοιπόν, τι μπορούμε να κάνουμε? Λοιπόν, υπάρχουν πολλές στρατηγικές και προϊόντα εκεί έξω. Μία από τις πιο σημαντικές είναι η Gatsby, μια στατική γεννήτρια τοποθεσιών (είμαι βέβαιος ότι το έχετε ακούσει μέχρι τώρα) η οποία επικεντρώνεται σε μεγάλο βαθμό στη βελτιστοποίηση της απόδοσης. Το ζήτημα με το Gatsby είναι ότι πρέπει να δημιουργήσει όλες τις σελίδες και τις υποσελίδες σας κατά το χρόνο σύνταξης που δεν λειτουργεί πραγματικά όταν έχετε τοποθεσίες που συνδέονται με ένα CMS που ενημερώνεται καθημερινά και φιλοξενεί εκατομμύρια άρθρα - κάτι ακριβώς που χρειαζόμαστε για τοποθεσίες ειδήσεων μέσων ενημέρωσης. Αυτός είναι ο λόγος που χρησιμοποιούμε την Επόμενη καθώς και την τροποποίησή της ώστε να ταιριάζει στις ανάγκες μας.

Εισάγετε μερική ενυδάτωση

Για την επίλυση των προαναφερθέντων προβλημάτων ήρθε με κάτι που θέλαμε να ονομάσουμε μερική ενυδάτωση.

Εάν εξετάσατε αυτό το θέμα, πιθανότατα θα έχετε συναντήσει όρους όπως η προοδευτική ενυδάτωση ή η τεμπέληλη ενυδάτωση. Δεν σημαίνουν όλοι το ίδιο πράγμα συγκεκριμένα, αλλά όλες είναι αλληλένδετες και ανήκουν στην ίδια σφαίρα.

Η βασική ιδέα πίσω από την έκδοση της μερικής ενυδάτωσης είναι: Αντί να κάνετε SSR και στη συνέχεια να στείλετε ολόκληρη την εφαρμογή σας στον πελάτη σας, μόνο τμήματα του JavaScript της εφαρμογής θα αποστέλλονται στον πελάτη για να ενυδατώνει τα τμήματα του ιστότοπού σας, . Αν δημιουργούσατε έναν ιστότοπο χρησιμοποιώντας μια τέτοια μέθοδο, θα έχετε πολλές μικροσκοπικές εφαρμογές React με πολλαπλές ρίζες απόδοσης στον κατά τα άλλα στατικό ιστότοπό σας.

Κάνοντας τα πράγματα με αυτόν τον τρόπο θα πρέπει να δώσετε στον ιστότοπό σας μια τεράστια αύξηση επιδόσεων, διότι αυτό που καταλήγετε στη ναυτιλία είναι απλό HTML, CSS και το ελάχιστο ποσό JavaScript που απαιτείται για τη σελίδα σας. Ένα πράγμα που πρέπει να σημειωθεί, κατά τη μέτρηση των επιδόσεων δεν πρέπει μόνο να υπολογίζει το χρόνο φόρτωσης, αλλά και την ανάλυση και την εκτέλεση του χρόνου επίσης.

Μπορείτε επίσης να επιλέξετε να εφαρμόσετε κατάλληλες στρατηγικές απόδοσης πάνω από όλα αυτά, όπως το σχίσιμο κώδικα, τη φροντίδα για την αργή εκκίνηση του TCP και την κρίσιμη διαδρομή απόδοσης κλπ.

Η εφαρμογή μας

Η εφαρμογή μας αποτελείται από 2 πακέτα:

  • Η βιβλιοθήκη Preact για μερική ενυδάτωση που ονομάζεται pool-attendant-preact
  • Το plugin Next.js ονομάζεται επόμενη υπερ-απόδοση

Η τελευταία βιβλιοθήκη είναι απλώς ένα plugin για το Next.js που χρησιμοποιεί pool-attendant-preact, οπότε ας επικεντρωθούμε στο pool-attendant-preact. Μπορώ να γράψω μια επόμενη θέση στην επόμενη σούπερ απόδοση σε κάποιο στάδιο στο μέλλον.

πισίνα-συνοδός-preact

Διάταξη με κεφαλίδα, σώμα, πλευρική γραμμή και 2 ενεργά στοιχεία

Φανταστείτε αυτή τη διάταξη και ας υποθέσουμε ότι τα γκρίζα κουτιά είναι στοιχεία που μπορούν να είναι εντελώς στατικά και θέλετε τα μοβ να είναι αλληλεπιδραστικά. Για παράδειγμα, το μεγαλύτερο θα μπορούσε να είναι ένα feed Twitter και το μικρότερο ένα μικρό εργαλείο ψηφοφορίας. Επομένως, πρέπει να εφαρμόσουμε JavaScript σε αυτά τα στοιχεία για να τα κάνουμε διαδραστικά και θέλουμε να αφήσουμε τα υπόλοιπα ως στατικά στοιχεία.

Ένα παράδειγμα υλοποίησης για αυτό χρησιμοποιώντας το pool-attendant-preact θα μπορούσε να μοιάζει με αυτό:

Οι γραμμές 3-8 είναι όλα τα συστατικά που θέλουμε να εμφανίσουμε, αυτά τα στοιχεία θα αποτυπωθούν στον διακομιστή και έπειτα θα σταλούν ως HTML και CSS στον πελάτη χωρίς καμία JavaScript.

Οι γραμμές 10 & 11 είναι όπου σημειώνουμε τις συνιστώσες TwitterFeed και Poll για ενυδάτωση και παίρνουμε ένα νέο στοιχείο σε αντάλλαγμα. Οι γραμμές 18 & 19 είναι όπου τις χρησιμοποιούμε.

Η γραμμή 22 είναι ύψιστης σημασίας. Αυτό είναι ένα στοιχείο που ενίει δεδομένα ενυδάτωσης (στηρίγματα και ονόματα συστατικών) στη σελίδα.

Αλλά επιτρέψτε μου να εξηγήσω. Όταν κάνουμε μια κανονική ενυδάτωση με την αντίδραση, ο κώδικας σας μοιάζει με αυτό:

Υπάρχουν 2 προβλήματα που πρέπει να λύσουμε εδώ όταν κάνουμε μερική ενυδάτωση

  1. Το ReactDOM.hydrate λειτουργεί σε έναν κόμβο ρίζας στο DOM, τον κόμβο που χρησιμοποιεί ως σημείο εκκίνησης για την ενυδάτωση. Αυτός ο κόμβος ρίζας πρέπει να περιέχει ένα δομημένο DOM server που αντιστοιχεί στα στοιχεία και την κατάσταση της εφαρμογής σας. Η αλίευση: Πρέπει να ονομάσετε ρητά έναν κόμβο DOM που θα λειτουργεί ως κόμβος ρίζας. Σε αυτό το παράδειγμα, αυτό είναι απλό, μπορείτε να δώσετε στον κόμβο αυτό ένα id, χρησιμοποιήστε το document.getElementbyId και στη συνέχεια ρίξτε αυτόν τον κόμβο στο ReactDOM.hydrate και είστε έτοιμοι!
    Μερική ενυδάτωση από την άλλη πλευρά σημαίνει ότι θα έχετε πολλά στοιχεία DOM στη στατική σελίδα που χρειάζεστε για να κάνετε ενυδάτωση. Δεν θα θέλατε να τα ονομάσετε όλα αυτά που θα ήταν κουραστική δουλειά για τον προγραμματιστή.
  2. Τι γίνεται αν το HydrateTwitterFeed ή το HydratedPoll χρειάζονται στηρίγματα που πρέπει να μεταφερθούν σε αυτά; Πείτε κάτι σαν το . Αν θέλουμε να τρέξουμε ReactDOM.hydrate (, rootElementOnThePage) από πού θα πάρουμε το luke_schmuke από; Πώς θα γνωρίζει μια στατική σελίδα αυτό; Πρέπει να τα αποθηκεύσουμε και να τα στείλουμε στον πελάτη.

Λύση

Ο τρόπος με τον οποίο αντιμετωπίσαμε αυτό το πρόβλημα μπορεί να γίνει κατανοητός από την εφαρμογή της με την Υδραυλική:

Ας ρίξουμε μια πιο προσεκτική ματιά σε αυτό: με την Υδροποίηση λειτουργεί με την τεχνική συστατικού υψηλότερης τάξης, το συστατικό της υψηλότερης σειράς επιστρέφει το αρχικό συστατικό μαζί με τα αρχικά του αναλλοίωτα στηρίγματα, αλλά το προετοιμάζει και με μια ετικέτα