NextJS和组件库使用样式化的组件,未正确水合

ljsrvy3e  于 2023-06-22  发布在  其他
关注(0)|答案(1)|浏览(121)

我正在尝试为一个新的nextJS应用程序构建一个组件库。nextJS应用程序有“app router”。
样式化的组件在我使用的时候工作得很好,直接集成在nextJS代码中,当我想使用组件库时,问题就出现了,我有。
我做了nextJS推荐的一切,我在next.config.js中设置了以下内容

/** @type {import('next').NextConfig} */
const nextConfig = {
  compiler: {
    styledComponents: {
      // Enabled by default.
      cssProp: true,
    },
  },
}

module.exports = nextConfig

我还根据nextJS定义包含了“StyledComponentsRegistry”。
我已经配置了库,以便它是使用汇总构建的。
首先,我尝试将styled-components保持为peerDependency,并在rollup中将其添加为“external”。这不起作用(它在浏览器中工作得很好,因为客户端代码工作得很好,但是在生成页面时,它在控制台中给了我一个错误。它基本上给了我以下错误,因为webpack无法包含样式化组件库styled_components__webpack_imported_module_0__ is not a function
因此我尝试将styled-components作为直接依赖项包含进来,并修改了StyledComponentsRegistry,使其也包含库中的styled-components版本。如下所示:

'use client';
 
import React, { useState } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
import { StyledComponentsServerStyleSheet, StyledComponentsStyleSheetManager } from 'skafte-cms';
 
export default function StyledComponentsRegistry({
  children,
}) {
  // Only create stylesheet once with lazy initial state
  // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
  const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());
  const [cmsStyledComponentsStyleSheet] = useState(() => new StyledComponentsServerStyleSheet());
 
  useServerInsertedHTML(() => {
    const styles = styledComponentsStyleSheet.getStyleElement();
    styledComponentsStyleSheet.instance.clearTag();
    const cmsStyles = cmsStyledComponentsStyleSheet.getStyleElement();
    cmsStyledComponentsStyleSheet.instance.clearTag();
    return <>{styles}{cmsStyles}</>;
  });
 
  if (typeof window !== 'undefined') return <>{children}</>;
 
  return (
    <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
      <StyledComponentsStyleSheetManager sheet={cmsStyledComponentsStyleSheet.instance}>
        {children}
      </StyledComponentsStyleSheetManager>
    </StyleSheetManager>
  );
}

这确实有效,但是当我加载页面时,我在控制台中得到一个错误,告诉我样式化组件没有被正确地水合(它只维护它的类,它是基于文件位置,而不是负责样式化的短类标识符)
任何帮助都很感激

woobm2wo

woobm2wo1#

要在NextJ中完全使用样式化组件,您需要:

  • 配置next.config.js或从Babel添加配置(根据您的情况选择更好的)
module.exports = {
  compiler: {
    styledComponents: {
      // Enable display of the component name along with the generated className (needed for debugging).
      displayName: true,
      // Enable SSR support
      ssr: true,
      // Optional
      fileName: false,
    },
  },
}

// babel.config.js

module.exports = {
  plugins: [
    [
      "babel-plugin-styled-components",
      {
        displayName: true,
        fileName: false,
        ssr: true,
      },
    ],
  ],
};
  • styled-components包作为peerDependency(yarn add styled-components --peer)安装到库中。
  • 在Rollup配置中,使用rollup-plugin-peer-deps-external插件,它将自动从包中排除库的package.json中指定为peerDependency的依赖项。
  • 将Babel集成插件添加到Rollup配置中,并在库的根目录中创建一个babel.config.js文件,其内容与上面演示的内容类似。
  • 这是因为您在应用程序级别设置的配置只适用于在应用程序本身中创建的组件。将无法正确处理来自外部库的代码。因此,您需要将新的Babel配置直接添加到库中,以便在构建Rollup时,babel-plugin-styled-components插件将进行必要的更改。

必须为库使用babel-plugin-styled-components插件,因为它将添加withConfig函数,其中包含开发期间调试所需的设置,并支持SSR,因此不会出现水合问题。
例如(输出包):

var StyledView = styled.div.withConfig({
  displayName: "StyledView",
  componentId: "sc-10aexlr-0"
})({
  padding: 10,
  border: "1px solid teal"
});

相关问题