От автора: CSS-in-JS может предоставить огромные преимущества для удобства обслуживания. Но для больших статически визуализируемых веб-сайтов использование простого CSS все еще имеет смысл.
Все больше и больше разработчиков переходят на CSS-in-JS, включая такие громкие имена, как Microsoft, Atlassian и … конкурс песни Евровидение! И хотя я не всегда был большим поклонником CSS-in-JS, даже я признаю его преимущества:
Это позволяет вам легко обмениваться переменными между JavaScript и CSS (просто не забывайте разделять их).
Это благо для инструментов, облегчающих удаление мертвого кода и доставку минимально возможного количества CSS.
И самое главное, это поощряет написание CSS в композитном стиле.
Похоже, что CSS-in-JS будет доминировать в дизайне веб-приложений в обозримом будущем. Но веб-приложения составляют лишь небольшую часть Интернета, потому что контент по-прежнему остается королем.
Если вы разработчик React, высока вероятность того, что вы будете работать со статически визуализируемым веб-сайтом. И, как я обнаружил при создании create-react-blog и Frontend Armory, использование CSS-in-JS для статически визуализируемых сайтов по-прежнему сопровождается несколькими оговорками …
В чем разница между статическим и серверным рендерингом?
Избегайте мелькания неустановленного контента
Идея статического рендеринга заключается в том, чтобы ускорить сайт путем предварительной рендеринга HTML-кода для каждой страницы, который затем может быть отображен пользователям до завершения загрузки JavaScript. Конечно, с помощью CSS-in-JS ваши стили, в основном содержатся в JavaScript. И это создает проблему — исходный HTML-код не будет работать до завершения загрузки JavaScript.
К счастью, команды, поддерживающие styled-components и emotion, позволяют решить эту проблему с помощью небольшого дополнительного кода. Например, styled-components предоставляет объект ServerStyleSheet, который позволяет статически визуализировать стили одновременно со статической визуализацией HTML. Затем вы просто отправляете статически визуализированный тег style как часть HTML:
render.js
import React from 'react@next' import { renderToString } from 'react-dom@next/server' import styled, { ServerStyleSheet } from 'styled-components' // стилизованный компонент const Button = styled.a` border: 2px solid palevioletred; border-radius: 3px; color: palevioletred; display: inline-block; font-family: sans-serif; padding: 0.5rem 1rem; margin: 0.5rem 1rem; ` // Элемент React, который будет фактически визуализироваться const pageContent = ( <Button as={'a'} href='https://www.youtube.com/watch?v=FpBJih02aYU' target='_blank'> Not my Gumdrop Buttons! </Button> ) // `ServerStyleSheet` может собирать стили из статически // визуализируемого HTML, а затем выводит их в виде строки тега <style>. const sheet = new ServerStyleSheet() const html = renderToString(sheet.collectStyles(pageContent)) const styleTags = sheet.getStyleTags() console.log('Static stylesheet:\n', styleTags) document.getElementById('root').innerHTML = styleTags+html
index.js
// DON'T DO THIS. It's a hack to tell styled-components // that server rendering is allowed, even in the browser. import 'react@next' const {StyleSheet} = require('styled-components').__DO_NOT_USE_OR_YOU_WILL_BE_HAUNTED_BY_SPOOKY_GHOSTS StyleSheet.reset(true) require('./render')
Предварительно выполнив рендеринг тега style и отправив его вместе с HTML, вы избежите появления нестандартного содержимого, но есть одна загвоздка. Поскольку ServerStyleSheet создает только стили для свойства initial, любое использование состояния компонента, componentDidMount или componentDidUpdate не будет отражено в стилях, представленных на сервере. Учитывая, что ваш предварительно визуализированный HTML имеет те же ограничения, это не должно быть проблемой. Но если вам нужна небольшая помощь в получении исходных данных для каждого из URL-адресов приложения, взгляните на Navi - маршрутизатор, созданный с учетом статического / серверного рендеринга. Но я отвлекся.
Статическое отображение стилей имеет еще одно преимущество: оно уменьшает количество CSS, которое требуется при начальной загрузке каждой страницы. Это связано с тем, что отображаемые теги style содержат только критический CSS, необходимый для предварительно обработанного HTML. Остальная часть CSS по-прежнему управляется с помощью JavaScript, что позволяет разделить его с помощью динамического import(). Это может быть очень важно для производительности … или может привести к тому, что многие мегабайты CSS будут недействительными при каждом обновлении — даже для обновлений, которые не затрагивают содержимое.
Встроенные и внешние таблицы стилей
Если вы посмотрите на сгенерированный тег style в приведенном выше примере, вы заметите, что он содержит атрибут data-styled. Это важно, потому что показывает, что styled-components привязаны к этому тегу style. Вы не можете надежно извлечь содержимое этого тега style в файл CSS, на который ссылается link. Что … может быть не такой уж большой проблемой?
Я имею в виду, почему вы все равно хотите поместить свои стили в отдельный файл?
Чтобы ответить на этот вопрос, рассмотрим основную причину статического рендеринга: он позволяет обслуживать JavaScript через CDN. Теперь, что касается ресурсов, обслуживаемых через CDN, они часто кэшируются со сроками истечения в далеком будущем. Таким образом, изменения в этих ресурсах требуют новых имен файлов, чтобы обойти кэш.
Естественно, изменения в именах файлов JavaScript потребуют соответствующих изменений в HTML, который ссылается на них. В результате HTML-файлы приложения не могут кэшироваться так же полно, как и теги style, встроенные в них. А благодаря дизайну Webpack изменения любого файла JavaScript в вашем проекте обычно требуют изменения каждого тега script и, следовательно, файла HTML в вашем приложении.
<!-- К примеру, этот тег скрипта: --> <script src="/static/js/runtime~main-47df755c101a4.js"></script> <!-- Может быть исправлен в это: --> <script src="/static/js/runtime~main-55ce84a0cc19b.js"></script>
Для приложений с небольшим количеством страниц, небольшим трафиком или небольшими тегами style это не проблема. Но для сайтов, ориентированных на контент, цифры могут значительно увеличиться. Например, предположим, что вы работаете с сайтом с 1000 страницами и 25 КБ критического CSS на каждой. Во всех HTML-файлах теперь у вас будет 25 МБ CSS в тегах style; и весь этот CSS должен передаваться в CDN при каждом изменении сайта — даже если ваше единственное изменение — исправление опечатки!
25 КБ критического CSS?! Критический CSS содержит только глобальные стили и стили для компонентов при начальном рендеринге одной страницы. Но некоторые компоненты могут содержать много стилей! Например, компонент <MarkdownDocument>, который содержит все возможные стили для любого возможного документа.
Вы все еще можете использовать CSS-in-JS
Является ли проблемой необходимость передавать в CDN весь встроенный CSS при каждом изменении? Это проблема, если пользователи не могут кэшировать критический CSS? Ответ — конечно, это зависит от. В частности, есть три условия, которые могут вызвать проблемы:
Если у вас много страниц с большим количеством критического CSS
Если ваш контент часто обновляется
Если у вас на сайте значительный трафик
В частности, если ваш сайт удовлетворяет всем этим трем условиям, есть большая вероятность, что вы сможете повысить производительность (и сэкономить на стоимости хостинга), переместив часть CSS в отдельные файлы CSS. Имейте в виду, что вы можете продолжать использовать CSS-in-JS наряду с обычным CSS или CSS Modules — вам просто нужно сохранить размер критического CSS-кода управляемым.
Конечно, styled-components — не единственный вариант. Другой популярный инструмент, emotion, во много схож с ними. Но есть также linaria - инструмент CSS-in-JS, который больше ориентирован на статический рендеринг. Если вы хотите использовать CSS-in-JS, но styled-components не удовлетворяют вашим требованиям, тогда вам определенно стоит попробовать linaria!
Но, возможно, вы предрасположены к стилизованным компонентам — в конце концов, у них есть звездная команда и огромное сообщество. И что важно, открытый исходный код! Команда Styled-Components в настоящее время работает над тем, чтобы сделать возможным извлечение кэшируемого CSS-кода, поэтому, если вы хотите внести свой вклад, посмотрите этот запрос.
Наконец, нужно сказать, что, хотя CSS-in-JS — отличный вариант, в нем нет абсолютной необходимости. Модули CSS и SASS решают большинство из тех же проблем, работая из коробки с create-react-app and create-react-blog. И CSS-in-JS, и простой CSS занимают свои ниши, и знание всех вариантов поможет вам выбрать правильный инструмент для работы.
Автор: James K Nelson
Источник: https://frontarm.com/
Редакция: Команда webformyself.