Стили компонента, импортированного из библиотеки компонентов, не применяются во время ssr

#reactjs #next.js #babeljs #styled-components #webpack-5

Вопрос:

Я столкнулся с проблемой, когда стили компонента, импортируемого из моей библиотеки компонентов, которая поставляется в комплекте с webpack 5, не применяются во время ssr.

У меня есть два проекта.

Приложение NextJS с SC. Импорт библиотеки компонентов:

Библиотека компонентов React с SC и поставляется в комплекте с webpack 5. Импортировано в мое приложение NextJS:

Библиотека компонентов добавляется как зависимость к приложению NextJS. Как только страница обновляется на клиенте, стили применяются правильно, только начальный рендеринг страницы не содержит стилей.

Я не знаю, связана ли проблема с SC или NextJS. Но если я не свяжу библиотеку компонентов с webpack, а вместо этого только транспилирую с помощью babel, используя эту конфигурацию:

 {
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ],
  "plugins":
  [
    "babel-plugin-styled-components"
  ]
}
 

затем NextJS выполняет ssr с примененными стилями.

Я настроил репозиторий с минимальным воспроизведением, чтобы любой мог проверить эту проблему, ниже приведены команды для компиляции библиотеки компонентов. Не стесняйтесь вносить свои изменения в предоставленный мной репозиторий.

Чтобы объединить библиотеку компонентов, запустите команду npm run build и установите для параметра main в package.json значение:

 "main": "./dist/index.js"
 

Для переноса с помощью babel запустите команду npm run transpile и установите для параметра main в package.json значение:

 "main": "./dist/index.transpiled.js"
 

Если я не предоставил достаточно информации для решения этой проблемы, пожалуйста, дайте мне знать, и я добавлю ее в сообщение.

Редактировать:

На скриншоте ниже вы можете увидеть два компонента. Вершина определяется в next.js приложение и визуализируется с помощью стилей. Нижняя часть импортируется из библиотеки компонентов и не имеет стилей при визуализации на сервере.

скриншот страницы

Комментарии:

1. Что вы подразумеваете под «начальным рендерингом»?

2. Я имею в виду рендеринг на стороне сервера, страницу, которая обслуживается из next.js сервер.

3. Проблема в том, что при компиляции с помощью webpack вы неправильно переносите babel-plugin-styled-components плагин?

4. @juliomalves Это может быть, потому что, как я уже говорил выше, когда я транспилирую с помощью babel с babel-plugin-styled-components плагином, он работает нормально. Только когда я использую webpack для компиляции всего этого, возникает эта проблема. Как бы мне продолжить выяснять, действительно ли проблема связана с использованием babel-plugin-styled-components с webpack?

Ответ №1:

Next изначально имеет предустановки babel, которыми вы должны воспользоваться. Я использую "babel-plugin-styled-components": "^1.13.2" в своем package.json , и эта настройка работает для меня с Webpack 5 / Next 11.x в моем babel.config.json :

 {
  "presets": ["next/babel"],
  "plugins": [
    [ 
      "styled-components", { 
        "ssr": true, 
        "displayName": true, 
        "preprocess": false 
      }
    ]
  ]
}
 

Комментарии:

1. Привет, спасибо за ответ. У меня настроена конфигурация babel так же, как и у вас в моем next.js приложение и оно рендерит компоненты, которые определены в моем next.js приложение, как и должно быть. Стили отсутствуют только у компонентов, импортированных из моей библиотеки внешних компонентов, когда next.js выполняет рендеринг на стороне сервера.

2. Вызывается единственный компонент, который я вижу в вашем репозитории библиотеки компонентов Wrapper , и вы его не экспортируете.

3. Экспортируется не стилизованный компонент, а компонент react, который возвращает стилизованный компонент. Извините, если я неясно задал вопрос, на какой компонент я ссылаюсь. Я добавил скриншот к вопросу, есть ли у вас представление о том, что может быть причиной этого?

4. Я не думаю, что вы можете обслуживать компонент react из приложения таким образом (вам нужно будет использовать следующий API: nextjs.org/docs/api-routes/introduction ). Если вы создаете библиотеку компонентов, есть инструменты, которые помогают с этой конкретной задачей — вы делаете много работы для себя, идя по этому пути.

5. Я не совсем понимаю, как Next API решит эту проблему, насколько я знаю, целью Next API является обработка вызовов api и операций с базой данных. Хотя я далек от эксперта в Next, поэтому мне, вероятно, не хватает некоторой информации здесь. Мой фактический проект состоит из нескольких независимых сервисов, которые используют множество одинаковых компонентов, поэтому для совместного использования общих компонентов между этими сервисами библиотека компонентов представляется мне лучшим способом достижения этой цели. Когда вы говорите «инструменты», имеете ли вы в виду какие-либо конкретные инструменты?

Ответ №2:

Вы должны ввести стили перед рендерингом, чтобы создать имя файла _document.js под pages/_document.js . попробуйте это

 import Document, { Head, Main, NextScript, Html } from 'next/document';
import { ServerStyleSheet } from 'styled-components';
export default class MainDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }

  render() {
    return (
      <Html lang='en'>
        <Head>
          <link
            href='https://fonts.googleapis.com/css2?family=Ubuntu'
            rel='stylesheet'
          />
        </Head>
        <body>
          <Main />
          <div id='modal-root' />
          <NextScript />
        </body>
      </Html>
    );
  }
}