从组件库导入的组件样式在 s-s-r 期间未应用
Posted
技术标签:
【中文标题】从组件库导入的组件样式在 s-s-r 期间未应用【英文标题】:Styles of component imported from component library not applied during s-s-r 【发布时间】:2021-12-21 11:19:38 【问题描述】:我遇到了一个问题,即从与 webpack 5 捆绑的组件库中导入的组件样式在 s-s-r 期间未应用。
我有两个项目。
带有 SC 的 NextJs 应用。导入组件库:
最小复制回购: https://github.com/tadej321/nextjs-test.git带有 SC 并与 webpack 5 捆绑在一起的 React 组件库。导入到我的 NextJs 应用程序中:
最小复制回购: https://github.com/tadej321/component-library-test.git组件库被添加为 NextJs 应用程序的依赖项。 一旦页面在客户端更新,样式就会正确应用,只是页面的初始渲染缺少样式。
我不知道是 SC 还是 NextJs 的问题。但是,如果我不将组件库与 webpack 捆绑,而是仅使用此配置与 babel 进行转译:
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins":
[
"babel-plugin-styled-components"
]
然后 NextJs 执行 s-s-r 并应用样式。
我已经建立了一个最小的repo repo,这样任何人都可以测试这个问题,下面是编译组件库的命令。随意将您的更改推送到我提供的存储库中。
要捆绑组件库,请运行 npm run build 命令并将 package.json 中的 main 设置为:
"main": "./dist/index.js"
要使用 babel 进行编译,请运行 npm run transpile 命令并将 package.json 中的 main 设置为:
"main": "./dist/index.transpiled.js"
如果我没有提供足够的信息来解决此问题,请告诉我,我会将其添加到帖子中。
编辑:
在下面的屏幕截图中,您可以看到两个组件。顶部在 next.js 应用程序中定义并使用样式呈现。底部是从组件库导入的,在服务端渲染时缺少样式。
screenshot of the page
【问题讨论】:
“初始渲染”是什么意思? 我的意思是在服务器端渲染,从 next.js 服务器提供的页面。 问题是当你使用 webpack 编译时你没有使用babel-plugin-styled-components
插件正确编译?
@juliomalves 可能是这样,因为正如我上面所说,当我使用带有babel-plugin-styled-components
插件的 babel 进行编译时,它工作正常。只有当我使用 webpack 编译整个东西时,才会出现这个问题。我将如何继续确定问题是否确实与将 babel-plugin-styled-components
与 webpack 一起使用?
【参考方案1】:
Next 原生具有您应该利用的 babel 预设。我在我的package.json
中使用"babel-plugin-styled-components": "^1.13.2"
,这个设置适用于我的babel.config.json
中的Webpack 5/Next 11.x:
"presets": ["next/babel"],
"plugins": [
[
"styled-components",
"s-s-r": true,
"displayName": true,
"preprocess": false
]
]
【讨论】:
您好,谢谢您的回答。我在 next.js 应用程序中设置了与您相同的 babel 配置,它正在渲染在我的 next.js 应用程序中定义的组件。当 next.js 执行服务器端渲染时,只有从我的外部组件库导入的组件缺少样式。 我在您的组件库 repo 中看到的唯一组件称为Wrapper
,您没有导出它。
styled 组件没有导出,react 组件是,返回的是styled 组件。抱歉,如果我的问题不清楚我指的是哪个组件。我已在问题中添加了屏幕截图,您是否知道可能导致此问题的原因?
我不认为你可以像这样从应用程序中提供 react 组件(你需要使用 Next API:nextjs.org/docs/api-routes/introduction)。如果您正在构建一个组件库,那么有一些工具可以帮助您完成该特定任务 - 您正在为自己做很多工作。
我不太明白 Next API 是如何解决这个问题的,据我所知 Next API 的目的是处理 api 调用和数据库操作。虽然我远不是 Next 的专家,所以我可能在这里缺少一些信息。我的实际项目由多个独立服务组成,它们都使用许多相同的组件,因此要在这些服务之间共享公共组件,在我看来,组件库是实现这一目标的最佳方式。当您说“工具”时,您是否想到了任何特定的工具?【参考方案2】:
您必须在渲染之前注入样式才能在pages/_document.js
下创建文件名_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>
);
【讨论】:
以上是关于从组件库导入的组件样式在 s-s-r 期间未应用的主要内容,如果未能解决你的问题,请参考以下文章