Обработка CSS на сервере приложений React

Next.js (React) и Nuxt.js (Vue) призваны упростить процесс рендеринга представлений вашего приложения на сервере.

При этом средство для рендеринга CSS в ваших компонентах React вы все еще должны выбрать самостоятельно, с учетом возможностей вашей разработки. Также вам понадобится решение для рендеринга CSS на сервере, чтобы стили были доступны.

В этом руководстве мы рассмотрим проблемы рендеринга CSS, а затем попробуем использовать styled-components и styled-jsx на сервере (в проекте Next.js).

Требования

Чтобы выполнить данный мануал, вам понадобится локальная установка Node.js (ее можно получить, следуя этим инструкциям для mac OSUbuntuDebianCentOS).

Это руководство было проверено с помощью следующих версий: 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-componentsGlamor – вот лишь краткий список инструментов для поддержки стилей компонентов.

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: , , ,

Добавить комментарий