Обработка CSS на сервере приложений React
Development, Java | Комментировать запись
Next.js (React) и Nuxt.js (Vue) призваны упростить процесс рендеринга представлений вашего приложения на сервере.
При этом средство для рендеринга CSS в ваших компонентах React вы все еще должны выбрать самостоятельно, с учетом возможностей вашей разработки. Также вам понадобится решение для рендеринга CSS на сервере, чтобы стили были доступны.
В этом руководстве мы рассмотрим проблемы рендеринга CSS, а затем попробуем использовать styled-components и styled-jsx на сервере (в проекте Next.js).
Требования
Чтобы выполнить данный мануал, вам понадобится локальная установка Node.js (ее можно получить, следуя этим инструкциям для mac OS, Ubuntu, Debian, CentOS).
Это руководство было проверено с помощью следующих версий: Node v16.2.0, npm v7.14.0, react v17.0.2, react-dom v17.0.2, next v10.2.3 и styled-compnents v5.3.0.
Шаблоны стилей в React
Существует несколько распространенных способов написания CSS в React. В зависимости от ситуации стили следует применять к приложению React одним из нижеописанных способов
Глобальные стили
Глобальные стили – это шаблон, подразумевающий включение таблиц стилей, размещенных в локальной сети или сети доставки контента (CDN).
Например:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" />
Это менее предпочтительный шаблон, поскольку он не способствует повторному использованию компонентов и не поощряет стилевую композицию.
Поскольку эти CSS-правила не привязаны непосредственно к конкретным элементам или компонентам, существует высокая вероятность возникновения конфликтов: в итоге компоненты взаимодействуют не так, как ожидалось при импорте, вложении или расширении.
Однако есть случаи, когда вы можете включить стили глобально – это, например, включение шрифтов, сброс и настройки CSS по умолчанию
Встроенные стили
Встроенные стили применяются непосредственно к элементам DOM или компонентам React с помощью свойства style в React. Его реализация очень похожа на встраивание атрибута style в HTML, но при этом используется JavaScript API под названием element.style.
Вот пример:
const titleStyle = { fontSize: '4rem'; lineHeight: '1.6'; color: '#222'; } <h1 style={titleStyle} {...props}>{props.children}<h1>
Этот шаблон поддерживает композицию стилей и компонентов, а также повторное использование.
Однако встроенные стили не предоставляют способ обработки состояний с помощью псевдоклассов и целевых псевдоэлементов. Для более крупных и сложных проектов вам может потребоваться более надежное решение.
Стили компонентов
Стили компонентов поддерживают повторное использование и помогают лучше компоновать стили и компоненты. Для реализации этого шаблона вам понадобится утилита или библиотека. Загрузчики стилей, styled-components, Glamor – вот лишь краткий список инструментов для поддержки стилей компонентов.
Styled-components – популярное средство для реализации CSS-in-JS. Это встроенные стили компонентов с большими возможностями (с поддержкой (псевдо) выбора, вложений и т.д.).
1: Настройка проекта
Для начала откройте свой терминал и создайте новую папку для тестового проекта:
mkdir css-ssr-next-example
Затем перейдите в новый каталог:
cd css-ssr-next-example
И выполните следующую команду для его инициализации:
npm init -y
Эта команда создаст файл package.json, который вы будете использовать для отслеживания зависимостей.
Теперь установите Next.js, React и React DOM:
npm install next@10.2.3 react@17.0.2 react-dom17.0.2
На этом этапе у нас есть новый проект с установленными пакетами Next.js, React и React DOM.
Примечание: Более современный подход к созданию проекта Next.js подразумевает использование create-next-app.
Теперь обновите файл package.json, чтобы запустить приложение Next.js с помощью сценария dev:
{ "name": "css-ssr-next-example", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "next" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "next": "^10.2.3", "react": "^17.0.2", "react-dom": "^17.0.2" } }
Затем создайте каталог pages:
mkdir pages
В этом каталоге создайте файл index.js со следующим содержимым:
import React from 'react'; const Index = () => <h1>Hi, new Next.js project</h1>; export default Index;
Теперь запустите скрипт dev, чтобы запустить сервер:
npm run dev
Если вы откроете localhost:3000 в веб-браузере, вы увидите сообщение:
Hi, new Next.js project
Сначала используйте в pages/index.js компонент Head из Next для нормализации стилей с помощью normalize.css:
import React from 'react'; import Head from 'next/head'; const Index = () => <div> <Head> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" /> <link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet" /> </Head> <h1>Hi, new Next.js project</h1> </div>; export default Index;
Затем создайте папку static в корневом каталоге вашего проекта Next.js:
mkdir static
В этом каталоге создайте файл base.css со следующим кодом CSS:
body { font-family: 'Raleway', sans-serif; color: #222; }
Импортируйте файл base.css на страницу Index (в файл pages/index.js):
// ... <Head> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" /> <link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet" /> <link rel="stylesheet" href="/static/base.css" /> </Head> // ...
После этого в браузере шрифт заметно изменится: вместо шрифта по умолчанию будет использоваться Raleway.
На данный момент у нас есть проект Next.js с поддержкой глобальных стилей.
2: Библиотека styled-components
Давайте воспользуемся библиотекой styled-components для стилизации компонентов.
Сначала установите эту библиотеку:
npm install styled-components@5.3.0
Затем создайте каталог components.
mkdir components
Поместите в этот каталог файл Button.js и внесите в этот файл такой код:
import React from 'react'; import styled from 'styled-components'; const ButtonBase = (props) => <button {...props}>{props.children}</button> const Button = styled(ButtonBase)` /* Rectangle 2: */ background: #0077E2; box-shadow: 0 2px 7px 0 rgba(120,137,149,0.25); border-radius: 3px; text-transform: uppercase; padding: 10px; color: #fff; border: #0077E2; ` export default Button;
Мы импортируем пакет styled-components как styled для стилизации компонента Button. ButtonBase возвращает скелет кнопки, а Button возвращает компонент со стилизованным ButtonBase.
Импортируйте компонент Button в index.js:
import React from 'react'; import Head from 'next/head'; import Button from '../components/Button' const Index = () => <div> <Head> .... </Head> <h1>Hi, new Next.js project</h1> <Button>Clicker</Button> </div>; export default Index;
Сохраните изменения и проверьте приложение в браузере. Под текстом появится кнопка с новым стилем.
Однако после жесткого обновления стиль кнопки больше не будет соответствовать ожидаемому: теперь стили кнопок отсутствуют, но при этом базовые стили почему-то остались нетронутыми. Используйте инструменты веб-разработчика для проверки источника страницы.
Контент рендерится на сервер, но стиль, связанный с кнопкой, на странице не отображается. С другой стороны, как мы видим по примененным стилям шрифтов, внешние файлы были успешно отрендерены на сервер.
Так что же пошло не так, что случилось со стилями компонентов? Взгляните на консоль:
Warning: Prop `className` did not match. Server: "sc-gtsrHT kbmjhF" Client: "sc-bdnxRM kbyRfM"
Вы найдете ошибку, указывающую на несоответствие в имени класса. Это связано с тем, что при перезагрузке содержимое сначала загружается с сервера.
К сожалению, библиотека styled-components не рендерится на сервере, что делает ее недоступной.
Примечание: Недавно в styled-components внедрили поддержку рендеринга на стороне сервера. Также вы можете обратиться к примеру Next.js with-styled-components.
Давайте попробуем устранить эту ошибку.
3: Библиотека styled-jsx
Команда разработчиков Next.js представила библиотеку под названием styled-jsx, чтобы помочь решить эту проблему. Она гарантирует, что стили, которые вы пишете, будут рендериться и на сервере, и в браузере, а не только в браузере.
styled-jsx уже идет в комплекте с Next.js по умолчанию, поэтому вам не нужно ничего устанавливать.
Вернитесь к компоненту Button в файл components/Button.js и измените его, чтобы использовать styled-jsx:
import React from 'react'; const Button = props => ( <button {...props}> {props.children} <style jsx>{` background: #0077e2; box-shadow: 0 2px 7px 0 rgba(120, 137, 149, 0.25); border-radius: 3px; text-transform: uppercase; padding: 10px; color: #fff; border: #0077e2; `}</style> </button> ); export default Button;
Перед закрывающим тегом корневого элемента в компоненте, который мы хотим стилизовать, можно создать элемент style с атрибутом jsx. В элементе style открываем фигурную скобку, содержащую строки шаблона. Строки должны содержать действительные стили CSS и сервер в качестве стиля вашего компонента.
Если ваш компонент состоит из нескольких элементов, вы можете использовать селекторы в styled-jsx:
import React from 'react'; const TitleAndButton = props => (<div {...props}> <h1 className="title">Hi Title</h1> <button>Clicker</button> <style jsx>{` h1.title { color: #222 } button { background: #0077e2; box-shadow: 0 2px 7px 0 rgba(120, 137, 149, 0.25); border-radius: 3px; text-transform: uppercase; padding: 10px; color: #fff; border: #0077e2; } `}</style> </div>); export default TitleAndButton;
Теперь вы можете импортировать и использовать компонент TitleAndButton на странице Index. Оба элемента будут стилизованы так, как и ожидалось.
Примечание: Вы также можете обратиться к with-styled-jsx от Next.js.
Библиотека styled-jsx – это один из подходов к рендерингу стилей на сервере в проектах Next.js.
Заключение
В этом мануале вы научились использовать styled-components и styled-jsx на сервере в проекте Next.js, а также ознакомились с рядом потенциальных проблем рендеринга CSS и научились их устранять.
Tags: CSS, Javascript, Node.js, React