资讯动态

Razzle 集成 styled-components:服务端渲染下 CSS-in-JS 样式的收集与注入完整指南

发布时间:2026/9/24 4:08:13 来源:尧图企业网站定制
前端构建工具前端构建后端【免费下载链接】razzle✨ Create server-rendered universal JavaScript applications with no configuration项目地址https://gitcode.com/gh_mirrors/ra/razzle点击查看免费下载本文围绕 Razzle 官方示例 with-styled-components 展开讲解如何在零配置的 universal同构React 应用中接入 styled-components并重点解决 CSS-in-JS 在服务端渲染SSR场景下的关键问题样式在服务端如何被收集、序列化为style标签并注入 HTML客户端又如何水合hydrate而不产生样式闪烁。读完本文你将掌握ServerStyleSheet、collectStyles、getStyleTags的完整调用链并能独立把 styled-components 接入自己的 Razzle 项目中。一、示例概览用一条命令启动一个 styled-components 同构应用with-styled-components 是 Razzle 官方仓库examples/目录下的一个最小化示例。它与 basic 示例的唯一区别在于组件样式不再依赖外部 CSS 文件而是通过 styled-components 以 CSS-in-JS 的方式内联在组件中并完成了服务端样式收集与注入。按 README 中的官方安装说明创建并启动示例只需两条命令npx create-razzle-app --example with-styled-components with-styled-components cd with-styled-components yarn startnpx create-razzle-app --example会从 packages/create-razzle-app 的模板库中拉取指定示例的完整目录结构到本地。启动后razzle start会同时编译并运行 server 与 client 两套 bundle默认端口 3000打开浏览器即可看到Welcome to Razzle页面以及一个使用 styled-components 渲染的按钮。示例的 package.json 提供了完整的脚本集{ scripts: { start: razzle start, build: razzle build, test: razzle test --envjsdom, start:prod: NODE_ENVproduction node build/server.js } }yarn start开发模式包含客户端与服务端 HMR热更新yarn build生产构建输出到build/目录yarn start:prod以生产模式直接运行构建产物中的服务端入口。二、目录结构与双入口约定示例遵循 Razzle 的同构应用约定核心源码位于src/目录文件作用src/index.js服务端进程入口负责启动 HTTP 服务并接入 HMRsrc/server.js服务端渲染核心创建 Express 应用、收集样式、输出 HTMLsrc/client.js浏览器端入口执行 React 水合hydratesrc/App.js根组件内含 styled-components 定义的样式组件src/App.test.js组件冒烟测试src/App.css普通 CSS非 CSS-in-JS 部分README 明确说明该示例满足了src/index.js服务端与src/client.js浏览器两个入口这是 Razzle 项目的基本结构要求。开发模式下Razzle 会分别以这两个文件为入口构建 server 与 client bundle生产模式下服务端入口编译为build/server.js供start:prod脚本运行。三、核心原理styled-components 的 SSR 样式收集三步曲CSS-in-JS 的样式在运行时才被注入 DOM。如果只做服务端渲染而不做任何处理首屏 HTML 中不会包含任何样式浏览器会先渲染出无样式的页面再等客户端脚本执行后注入样式造成 FOUC无样式内容闪烁。示例 src/server.js 的注释点明了解决思路Import the StyledComponents SSR util——通过 styled-components 提供的 SSR 工具在渲染过程中把组件用到的样式收集起来再以style标签的形式渲染进 HTML。整个流程由三步组成创建样式表const sheet new ServerStyleSheet();包裹渲染renderToString(sheet.collectStyles(App /))——在服务端渲染 React 组件树的同时把组件内所有 styled-components 生成的样式收集到sheet中生成标签const styleTags sheet.getStyleTags();——将收集到的样式序列化为可直接嵌入head的style标签字符串。3.1 完整代码拆解下面是 src/server.js 中渲染函数的核心实现import { ServerStyleSheet } from styled-components; export const renderApp (req, res) { // 1. 创建服务端样式表实例 const sheet new ServerStyleSheet(); // 2. 渲染组件的同时收集其中用到的所有样式 const markup renderToString(sheet.collectStyles(App /)); // 3. 生成所有 style 标签准备注入页面 const styleTags sheet.getStyleTags(); const html !doctype html html lang head ... ${cssLinksFromAssets(assets, client)} !-- 将组件中收集到的样式标签渲染进 DOM -- ${styleTags} /head body div idroot${markup}/div ${jsScriptTagsFromAssets(assets, client, defer crossorigin)} /body /html; return { html }; };注意styleTags被注入的位置它位于head内、静态 CSS 链接cssLinksFromAssets之后。这样既保证普通 CSS如 App.css优先加载又能让 CSS-in-JS 样式在页面渲染前就绪。renderApp返回{ html }而非直接发送响应这一设计使得渲染逻辑与 Express 解耦便于单元测试或更换 Web 框架。Express 部分随后将其接入路由server .disable(x-powered-by) .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get(/*, (req, res) { const { html } renderApp(req, res); res.send(html); });express.static(process.env.RAZZLE_PUBLIC_DIR)托管public/目录下的静态资源RAZZLE_PUBLIC_DIR是 Razzle 注入的公共目录环境变量get(/*)将所有路由回退到renderApp由 React 组件树接管页面渲染。3.2 资源清单与标签生成server.js顶部通过require(process.env.RAZZLE_ASSETS_MANIFEST)加载 Razzle 在构建时生成的资源清单manifestRAZZLE_ASSETS_MANIFEST是 Razzle 注入的构建产物清单路径。两个辅助函数据此生成 HTML 标签const cssLinksFromAssets (assets, entrypoint) { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset link relstylesheet href${asset} ).join() : : ; }; const jsScriptTagsFromAssets (assets, entrypoint, extra ) { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset script src${asset}${extra}/script ).join() : : ; };它们从清单中取出client入口对应的 CSS 与 JS 资源路径分别生成link与script标签。脚本标签额外携带defer crossorigin属性保证脚本在文档解析完成后按序执行并启用跨域资源共享。四、客户端入口水合与 HMRsrc/client.js 是浏览器端入口逻辑非常精简import { hydrate } from react-dom; import App from ./App; hydrate(App /, document.getElementById(root)); if (module.hot) { module.hot.accept(); }关键点在于使用hydrate而非render由于服务端已经输出完整的 HTML 与内联样式浏览器端只需把 React 组件树附着到#root节点上并绑定事件而不是重新创建 DOM。这既保证了首屏无闪烁也避免了重复渲染带来的性能浪费。module.hot.accept()则让开发模式下任何组件修改都能热更新到页面。五、组件定义styled-components 的最小用法src/App.js 展示了 styled-components 最基础的用法import ./App.css; import React from react; import styled from styled-components; const Button styled.button border-radius: 3px; padding: 0.25em 1em; margin: 0 1em; background: transparent; color: palevioletred; border: 2px solid palevioletred; ; const App () ( div Welcome to Razzle. ButtonStyledComponent button/Button /div ); export default App;styled.button创建一个带样式的按钮组件模板字符串中的 CSS 会被 styled-components 编译并在运行时注入。在 SSR 流程中collectStyles(App /)会扫描整棵组件树把这个Button的样式规则收集进ServerStyleSheet最终以style标签形式出现在服务端输出的 HTML 中。客户端水合后Button的类名与样式与服务端完全一致因此不会出现样式闪烁或类名不匹配的问题。src/App.test.js 提供了基础冒烟测试在 jsdom 环境中渲染App /验证组件不会崩溃。razzle test --envjsdom即运行这类测试。六、服务端入口进程启动与 HMR 衔接src/index.js 是服务端进程入口负责把server.js导出的 Express 应用挂载到端口并接入 HMRlet app require(./server).default; if (module.hot) { module.hot.accept(./server, function() { console.log( HMR Reloading ./server...); try { app require(./server).default; } catch (error) { console.error(error); } }); console.info(✅ Server-side HMR Enabled!); } const port process.env.PORT || 3000; export default express() .use((req, res) app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log( Started on port ${port}); });实现要点通过module.hot.accept(./server)监听服务端模块更新修改server.js或组件后无需重启进程即可生效使用process.env.PORT || 3000支持环境变量覆盖端口便于部署用app.handle(req, res)把请求转交给 Express 应用实例支持app变量被 HMR 替换。七、依赖清单与版本说明package.json 中与 styled-components 直接相关的依赖为dependencies: { express: ^4.17.1, react: ^17.0.1, react-dom: ^17.0.1, react-is: ^17.0.1, styled-components: ^5.1.0 }两点值得注意react-is是 styled-components 5.x 的运行时依赖styled-components 内部使用react-is判断 React 元素类型因此示例显式声明了与 React 同版本的react-is避免解析歧义razzle与razzle-dev-utils均锁定为 4.2.15与仓库当前版本一致示例由仓库的scripts/update-examples.js脚本统一维护依赖版本保证开箱即用。从源码结构看示例未配置任何自定义 razzle.config.js完全依赖 Razzle 内置的 Babel 与 Webpack 预设——这也正是零配置接入 styled-components的体现你只需安装依赖、写好组件SSR 样式收集的代码仅在server.js中寥寥数行。八、从示例到实战把 styled-components 接入你自己的 Razzle 项目参考本示例在自有 Razzle 项目中接入 styled-components 只需四步安装依赖yarn add styled-components react-isreact-is版本与 React 保持一致改造服务端渲染在src/server.js中引入ServerStyleSheet用sheet.collectStyles包裹组件树并将sheet.getStyleTags()注入head为防内存泄漏可在响应结束后调用sheet.seal()示例为最小化演示未展示生产环境建议补充保持客户端水合client.js使用hydrate挂载到#root编写样式组件用styled标签模板定义组件样式无需任何 Webpack/Babel 额外配置。通过以上流程你的 Razzle 应用即可获得服务端输出完整样式 → 首屏无闪烁 → 客户端无缝水合的完整体验这正是本示例要传达的核心模式。延伸阅读examples/basic不含 styled-components 的基础同构示例可与本文对照理解样式收集部分新增了什么examples/with-custom-webpack-config如需进一步定制构建可参考自定义 Webpack 配置的示例packages/razzleRazzle 核心包含构建、启动与测试的全部实现。赞分享前端构建工具前端构建后端【免费下载链接】razzle✨ Create server-rendered universal JavaScript applications with no configuration项目地址https://gitcode.com/gh_mirrors/ra/razzle点击查看免费下载相关推荐React Static 集成 styled-componentsCSS-in-JS 服务端渲染SSR插件完整指南React Static 集成 styled componentsCSS in JS 服务端渲染SSR插件完整指南 本文围绕 React Static 官前端开发工具Razzle JSXStyle 通用渲染实战服务端按请求收集 Critical CSS 并注入 headRazzle JSXStyle 通用渲染实战服务端按请求收集 Critical CSS 并注入 head Razzle 的 with jsxstyle前端构建工具前端构建后端spin.js中的CSS-in-JS使用styled-components集成spin.js中的CSS in JS使用styled components集成 在现代前端开发中CSS in JS方案已经成为组件化样式管理的主流选择。本文UI组件前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价