CSS-in-JS и статический рендеринг

CSS-in-JS и статический рендеринг

От автора: 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.