Οι συναλλαγές του CSS-in-JS

Φωτογραφία του Artem Bali

Πρόσφατα έγραψα μια επισκόπηση υψηλότερου επιπέδου του CSS-in-JS, που μιλούσε ως επί το πλείστον για τα προβλήματα που αυτή η προσέγγιση προσπαθεί να λύσει. Οι συγγραφείς της βιβλιοθήκης σπάνια επενδύουν χρόνο στην περιγραφή των συμβιβασμών της λύσης τους. Μερικές φορές είναι επειδή είναι πολύ προκατειλημμένες, και μερικές φορές απλά δεν ξέρουν πώς χρησιμοποιούν οι χρήστες το εργαλείο. Επομένως, αυτή είναι μια προσπάθεια να περιγράψω τις συμφωνίες που έχω δει μέχρι στιγμής. Νομίζω ότι είναι σημαντικό να αναφέρω ότι είμαι ο συγγραφέας του JSS, οπότε θα πρέπει να θεωρηθεί προκατειλημμένος.

Κοινωνικές επιπτώσεις

Υπάρχει ένα στρώμα ανθρώπων που εργάζονται στην πλατφόρμα ιστού και δεν γνωρίζουν κανένα JavaScript. Αυτοί οι άνθρωποι πληρώνονται για να γράψουν HTML και CSS. Το CSS-in-JS έχει κάνει τεράστιο αντίκτυπο στη ροή εργασιών των προγραμματιστών. Μια πραγματικά μεταβαλλόμενη αλλαγή δεν μπορεί ποτέ να γίνει χωρίς να μείνουν πίσω κάποιοι άνθρωποι. Δεν ξέρω αν το CSS-in-JS πρέπει να είναι ο μόνος τρόπος, αλλά η μαζική υιοθέτηση είναι ένα σαφές σημάδι των προβλημάτων με τη χρήση του CSS στις σύγχρονες εφαρμογές.

Ένα μεγάλο μέρος του προβλήματος είναι η αδυναμία μας να επικοινωνήσουμε με ακρίβεια τις περιπτώσεις χρήσης όπου το CSS-in-JS λάμπει και πώς να το χρησιμοποιήσει σωστά για μια εργασία. Πολλοί ενθουσιώδες του CSS-in-JS έχουν επιτύχει στην προώθηση της τεχνολογίας, αλλά πολλοί επικριτές δεν μίλησαν για τις συμφωνίες με εποικοδομητικό τρόπο, χωρίς να κάνουν φθηνά κούνια στα εργαλεία. Ως αποτέλεσμα, αφήσαμε πολλές συμμορίες κρυμμένες και δεν καταβάλλουμε έντονες προσπάθειες για να δώσουμε τις εξηγήσεις και τις λύσεις.

Το CSS-in-JS είναι μια προσπάθεια να κάνετε πιο περίπλοκες περιπτώσεις χρήσης πιο εύκολα, οπότε μην το πιέζετε εκεί όπου δεν είναι απαραίτητο!

Χρόνος εκτέλεσης

Όταν το CSS δημιουργείται από το JavaScript κατά τη διάρκεια εκτέλεσης, στο πρόγραμμα περιήγησης υπάρχει εγγενής επιβάρυνση. Το κόστος εκτέλεσης διαφέρει από βιβλιοθήκη στη βιβλιοθήκη. Αυτό είναι ένα καλό γενικό σημείο αναφοράς, αλλά βεβαιωθείτε ότι έχετε κάνει τις δικές σας δοκιμές. Οι μεγάλες διαφορές κατά το χρόνο εκτέλεσης εμφανίζονται ανάλογα με την ανάγκη πλήρους ανάλυσης CSS των συμβολοσειρών προτύπων, του αριθμού των βελτιστοποιήσεων, των λεπτομερειών υλοποίησης δυναμικών στυλ, του αλγόριθμου κατακερματισμού και του κόστους ενσωμάτωσης πλαισίου. *

Εκτός από τις πιθανές γενικές δαπάνες χρόνου εκτέλεσης, θα πρέπει να εξετάσετε 4 διαφορετικές στρατηγικές δέσμευσης, επειδή ορισμένες βιβλιοθήκες CSS-in-JS υποστηρίζουν πολλαπλές στρατηγικές και εξαρτάται από τον χρήστη να τις εφαρμόσει. *

Στρατηγική 1: Μόνο για την εκτέλεση χρόνου

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

Το εμπόριο της γενιάς κατά τη διάρκεια της εκτέλεσης είναι η αδυναμία παροχής στυλ περιεχομένου στο αρχικό στάδιο, καθώς το έγγραφο αρχίζει να φορτώνεται. Αυτή η προσέγγιση ταιριάζει συνήθως σε εφαρμογές χωρίς περιεχόμενο που μπορεί να είναι χρήσιμο αμέσως. Συνήθως, τέτοιες εφαρμογές απαιτούν αλληλεπιδράσεις χρήστη πριν μπορέσουν πραγματικά να γίνουν χρήσιμες για έναν χρήστη. Συχνά, τέτοιες εφαρμογές λειτουργούν με περιεχόμενο που είναι τόσο δυναμικό που καθίσταται ξεπερασμένο από τη στιγμή που το φορτώνετε, οπότε πρέπει να δημιουργήσετε ένα δίκτυο ενημέρωσης από νωρίς, για παράδειγμα, το Twitter. Επιπλέον, όταν ένας χρήστης είναι συνδεδεμένος, δεν χρειάζεται να παρέχει HTML για SEO.

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

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

Στρατηγική 2: Γενιά εκτέλεσης με κρίσιμη CSS

Το κριτικό CSS είναι το ελάχιστο ποσό CSS που απαιτείται για να στυλισθεί η σελίδα στην αρχική της κατάσταση. Αποδίδεται χρησιμοποιώντας μια ετικέτα στυλ στην κεφαλή του εγγράφου. Αυτή η τεχνική χρησιμοποιείται ευρέως με και χωρίς το CSS-in-JS. Και στις δύο περιπτώσεις, είναι πιθανό να διπλασιαστεί ο φόρτος των κανόνων CSS, μία φορά ως μέρος του κρίσιμου CSS και μία φορά ως μέρος της δέσμης JavaScript ή CSS. Το μέγεθος του Κρίσιμου CSS μπορεί να είναι αρκετά μεγάλο, ανάλογα με το μέγεθος του περιεχομένου. Συνήθως, το έγγραφο δεν θα αποθηκευτεί προσωρινά.

Χωρίς Critical CSS, μια εφαρμογή μονής σελίδας με στατικό περιεχόμενο, με CSS-in-JS, θα πρέπει να δείχνει placeholders αντί για περιεχόμενο. Αυτό είναι κακό επειδή θα μπορούσε να ήταν χρήσιμο για έναν χρήστη πολύ νωρίτερα, βελτιώνοντας την προσβασιμότητα σε συσκευές χαμηλού τέλους και για συνδέσεις χαμηλού εύρους ζώνης.

Με το κριτικό CSS, η γενιά CSS μπορεί να γίνει σε μεταγενέστερο στάδιο, χωρίς να εμποδίζει το UI στην αρχική φάση. Ωστόσο, προειδοποιείτε ότι στις κινητές συσκευές χαμηλού επιπέδου, ηλικίας περίπου 5 ετών, η παραγωγή CSS από τη JavaScript μπορεί να έχει αρνητικό αντίκτυπο στην απόδοση. Εξαρτάται έντονα από την ποσότητα του CSS που παράγεται και τη βιβλιοθήκη που χρησιμοποιείται, επομένως δεν μπορεί να γενικευθεί.

Η αντιστροφή αυτής της στρατηγικής είναι το κόστος της κρίσιμης εξαγωγής CSS και το κόστος της δημιουργίας CSS κατά την εκτέλεση.

Στρατηγική 3: Εξόρυξη χρονοπρογραμματισμού μόνο

Αυτή η στρατηγική είναι η προεπιλεγμένη στο διαδίκτυο χωρίς CSS-in-JS. Ορισμένες βιβλιοθήκες CSS-in-JS σας επιτρέπουν να εξαγάγετε το static CSS κατά τη δημιουργία του χρόνου. * Σε αυτήν την περίπτωση, δεν υπάρχει καθόλου δαπάνη χρόνου εκτέλεσης, το CSS αποδίδεται στη σελίδα χρησιμοποιώντας μια ετικέτα σύνδεσης. Το κόστος της γενιάς CSS καταβάλλεται μια φορά το χρόνο.

Υπάρχουν 2 σημαντικές συμφωνίες εδώ:

  1. Δεν μπορείτε να χρησιμοποιήσετε μερικές από τις προσφορές δυναμικών API CSS-in-JS κατά το χρόνο εκτέλεσης, επειδή δεν έχετε πρόσβαση στην πολιτεία. Συχνά δεν μπορείτε να χρησιμοποιήσετε τις ιδιότητες προσαρμοσμένων CSS, επειδή δεν υποστηρίζονται σε κάθε πρόγραμμα περιήγησης και δεν μπορούν να συμπληρωθούν από τη φύση κατά τη δημιουργία χρόνου. Σε αυτήν την περίπτωση, θα πρέπει να κάνετε εναλλακτικές λύσεις για δυναμική θεματολογία και κρατικό στυλ. *
  2. Χωρίς Critical CSS και με κενή προσωρινή μνήμη, θα μπλοκάρετε το πρώτο χρώμα, μέχρι να φορτωθεί η δέσμη CSS. Ένα στοιχείο σύνδεσης στην κεφαλή του εγγράφου εμποδίζει την απόδοση HTML.
  3. Μη ντετερμινιστική ιδιαιτερότητα με διαχωρισμό πακέτων βάσει σελίδας σε εφαρμογές μιας σελίδας. *

Στρατηγική 4: Εξόρυξη χρόνου κατασκευής με κρίσιμο CSS

Αυτή η στρατηγική δεν είναι επίσης μοναδική για το CSS-in-JS. Η πλήρης στατική εξαγωγή με κρίσιμη CSS παρέχει την καλύτερη απόδοση όταν εργάζεστε με μια πιο στατική εφαρμογή. Αυτή η προσέγγιση εξακολουθεί να έχει τις προαναφερθείσες συμφωνίες ενός στατικού CSS, εκτός από το ότι η ετικέτα σύνδεσης αποκλεισμού μπορεί να μετακινηθεί στο κάτω μέρος του εγγράφου.

Υπάρχουν 4 κύριες στρατηγικές αποτύπωσης CSS. Μόνο 2 από αυτά είναι ειδικά για το CSS-in-JS και κανένας από αυτούς δεν ισχύει για όλες τις βιβλιοθήκες.

Προσιτότητα

Το CSS-in-JS μπορεί να μειώσει την προσβασιμότητα όταν χρησιμοποιείται με λάθος τρόπο. Αυτό θα συμβεί όταν υλοποιηθεί ένας μεγάλος στατικός ιστότοπος περιεχομένου χωρίς την εξαγωγή κρίσιμων CSS, έτσι ώστε να μην είναι δυνατή η βαφή HTML πριν φορτωθεί και αξιολογηθεί η δέσμη JavaScript. Αυτό μπορεί επίσης να συμβεί όταν αποδίδεται ένα τεράστιο αρχείο CSS χρησιμοποιώντας μια ετικέτα συνδέσμου αποκλεισμού στην κεφαλή του εγγράφου, το οποίο είναι το πιο δημοφιλές τρέχον πρόβλημα με την παραδοσιακή ενσωμάτωση και δεν είναι συγκεκριμένο στο CSS-in-JS.

Οι προγραμματιστές πρέπει να αναλάβουν την ευθύνη για την προσβασιμότητα. Υπάρχει ακόμη μια ισχυρή λανθασμένη ιδέα ότι μια ασταθής σύνδεση στο διαδίκτυο είναι πρόβλημα των οικονομικά ασθενών χωρών. Έχουμε την τάση να ξεχνάμε ότι έχουμε προβλήματα διασύνδεσης κάθε μέρα όταν μπαίνουμε σε ένα υπόγειο σιδηροδρομικό σύστημα ή σε ένα μεγάλο κτίριο. Μια σταθερή κινητή σύνδεση χωρίς καλώδια είναι ένας μύθος. Δεν είναι εύκολο να έχετε μια σταθερή σύνδεση WiFi, για παράδειγμα, ένα δίκτυο WI-FI 2,4 GHz μπορεί να πάρει παρεμβολές από ένα φούρνο μικροκυμάτων!

Το κόστος του κρίσιμου CSS με την απόδοση του διακομιστή

Για να αποκτήσουμε κρίσιμη εξαγωγή CSS για το CSS-in-JS, χρειαζόμαστε SSR. Το SSR είναι μια διαδικασία δημιουργίας του τελικού κώδικα HTML για μια δεδομένη κατάσταση μιας εφαρμογής στο διακομιστή. Στην πραγματικότητα, μπορεί να είναι μια πολύπλοκη και δαπανηρή διαδικασία. Απαιτεί ένα ορισμένο αριθμό κύκλων CPU στο διακομιστή για κάθε αίτημα HTTP.

Το CSS-in-JS χρησιμοποιεί συνήθως το γεγονός ότι είναι συνδεδεμένο με τον αγωγό rendering HTML. * Γνωρίζει τι HTML αποδόθηκε και τι CSS χρειάζεται ώστε να είναι σε θέση να παράγει το απόλυτο ελάχιστο ποσό του. Το κριτικό CSS προσθέτει επιπλέον έξοδα για την απόδοση HTML στο διακομιστή, επειδή το CSS πρέπει επίσης να μεταγλωττιστεί σε μια τελική συμβολοσειρά CSS. Σε μερικά σενάρια, είναι δύσκολο ή και αδύνατο να αποθηκευτεί προσωρινά στον server.

Δημιουργία μαύρου κουτιού

Πρέπει να γνωρίζετε πώς μια βιβλιοθήκη CSS-in-JS που χρησιμοποιείτε αποδίδει το CSS. Για παράδειγμα, οι άνθρωποι συχνά δεν γνωρίζουν πώς το Styled Components και το Emotion εφαρμόζουν δυναμικά στυλ. Τα δυναμικά στυλ είναι μια σύνταξη που επιτρέπει τη χρήση λειτουργιών JavaScript μέσα στη δήλωση στυλ. Αυτές οι λειτουργίες δέχονται υποδείξεις και επιστρέφουν ένα μπλοκ CSS.

Προκειμένου να διατηρηθεί η εξειδίκευση της παραγγελίας πηγής συνεπής, και οι δύο παραπάνω βιβλιοθήκες δημιουργούν έναν νέο κανόνα CSS εάν περιέχει μια δυναμική δήλωση και τις ενημερώσεις στοιχείων με νέα στηρίγματα. Για να καταδείξω τι εννοώ, δημιούργησα αυτό το sandbox. Στο JSS αποφασίσαμε να πάρουμε ένα διαφορετικό tradeoff, το οποίο μας επιτρέπει να ενημερώνουμε τις δυναμικές ιδιότητες χωρίς να δημιουργούμε νέους κανόνες CSS. *

Απότομη καμπύλη εκμάθησης

Για τους ανθρώπους που είναι εξοικειωμένοι με το CSS, αλλά είναι νέοι στη JavaScript, το αρχικό ποσό εργασίας για να φτάσετε στην ταχύτητα με το CSS-in-JS μπορεί να είναι αρκετά μεγάλο.

Δεν χρειάζεται να είστε επαγγελματίας προγραμματιστής JavaScript για να γράψετε CSS-in-JS, μέχρι το σημείο όπου εμπλέκεται πολύπλοκη λογική. Δεν μπορούμε να γενικεύσουμε την πολυπλοκότητα του styling, καθώς πραγματικά εξαρτάται από την περίπτωση χρήσης. Σε περιπτώσεις όπου το CSS-in-JS γίνεται πολύπλοκο, είναι πιθανό η εφαρμογή με το CSS σε βανίλια να είναι ακόμη πιο περίπλοκη.

Για βασικό στυλ CSS-in-JS, πρέπει να γνωρίζουμε πώς να δηλώνουμε μεταβλητές, πώς να χρησιμοποιούμε συμβολοσειρές προτύπων και να παρεμβάλλουμε τις τιμές JavaScript. Αν χρησιμοποιείται αντικειμενικός συμβολισμός, πρέπει να γνωρίζουμε πώς να δουλεύουμε με αντικείμενα JavaScript και τη σύνταξη βάσει αντικειμένων συγκεκριμένης βιβλιοθήκης. Εάν εμπλέκεται δυναμικό στυλ, πρέπει να γνωρίζετε πώς να χρησιμοποιείτε τις λειτουργίες JavaScript και τους όρους.

Συνολικά υπάρχει μια καμπύλη μάθησης, δεν μπορούμε να την αρνηθούμε. Αυτή η καμπύλη μάθησης συνήθως δεν είναι πολύ μεγαλύτερη από τη μάθηση του Sass. Στην πραγματικότητα, δημιούργησα αυτό το μάθημα για να το καταδείξω αυτό.

Δεν υπάρχει διαλειτουργικότητα

Τα περισσότερα αρχεία CSS-in-JS δεν είναι διαλειτουργικά. Αυτό σημαίνει ότι τα στυλ που γράφονται χρησιμοποιώντας μια βιβλιοθήκη δεν μπορούν να αναπαραχθούν χρησιμοποιώντας μια διαφορετική βιβλιοθήκη. Πρακτικά σημαίνει ότι δεν μπορείτε να αλλάξετε εύκολα ολόκληρη την εφαρμογή σας από μια υλοποίηση στην άλλη. Σημαίνει επίσης ότι δεν μπορείτε εύκολα να μοιράζεστε το UI σας στο NPM χωρίς να μεταφέρετε τη βιβλιοθήκη CSS-in-JS της επιλογής σας στη δέσμη των καταναλωτών εκτός εάν έχετε μια στατική εξόρυξη χρόνου δημιουργίας για το CSS.

Έχουμε αρχίσει να δουλεύουμε με τη μορφή του ISTF που υποτίθεται ότι πρέπει να διορθώσει αυτό το πρόβλημα, αλλά δυστυχώς δεν είχαμε ακόμα χρόνο να το φτάσουμε σε κατάσταση παραγωγής.

Πιστεύω ότι η κοινή χρήση επαναχρησιμοποιήσιμων συστατικών του αγνωστικού πλαισίου UI στο δημόσιο τομέα εξακολουθεί να είναι ένα γενικά δύσκολο να επιλυθεί πρόβλημα.

Κίνδυνοι ασφαλείας

Είναι δυνατή η εισαγωγή διαρροών ασφαλείας με το CSS-in-JS. Όπως συμβαίνει και με τις εφαρμογές που αφορούν την πλατφόρμα πελάτη, θα πρέπει να αποφεύγετε τις εισερχόμενες από τον χρήστη πριν την απόδοση, πάντα.

Αυτό το άρθρο θα σας δώσει περισσότερη γνώση και ορισμένα παραδειγματικά παραδείγματα.

Μη αναγνωρίσιμα ονόματα κλάσεων

Μερικοί άνθρωποι εξακολουθούν να πιστεύουν ότι είναι σημαντικό να διατηρούμε νόημα αναγνωρίσιμα ονόματα τάξεων στο διαδίκτυο. Επί του παρόντος, πολλές βιβλιοθήκες CSS-in-JS παρέχουν σημαντικά ονόματα τάξεων με βάση το όνομα της δήλωσης ή το όνομα του συστατικού σε κατάσταση ανάπτυξης. Ορισμένες από αυτές σας επιτρέπουν να προσαρμόσετε τη λειτουργία γεννήτριας κλάσης.

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

συμπέρασμα

Οι συναλλαγές υπάρχουν, και πιθανότατα δεν τις ανέφερα καν. Αλλά οι περισσότεροι από αυτούς δεν ισχύουν γενικά σε όλα τα CSS-in-JS. Εξαρτάται από τη βιβλιοθήκη που χρησιμοποιείτε και από τη χρήση της.

* Θα χρειαστεί ένα ειδικό άρθρο για να εξηγήσετε αυτή την πρόταση. Επιτρέψτε μου να ξέρω στο Twitter (@ oleg008) για το ποια θα θέλατε να διαβάσετε περισσότερα.