用途
本技能面向在 Next.js 中使用 Fluent UI React v9 的开发者,解决服务端渲染(SSR)与 React Server Components(RSC)带来的集成难题。Fluent UI 使用 Griffel 做 CSS-in-JS 样式,默认在运行时生成样式;在服务端渲染环境中,样式必须在服务端渲染期间收集并注入 HTML,否则会出现无样式内容闪烁(FOUC)或 hydration 不匹配。此外,Fluent UI 组件依赖 React context、state 和 effect,属于仅客户端 API,必须放在 'use client' 边界内。
主要能力
- 提供 App Router(Next.js 13.4+)与 Pages Router 两套集成方案。
- App Router:通过 app/providers.tsx 中的 'use client' 边界、useServerInsertedHTML 钩子与 Griffel 的 renderToStyleElements 实现 SSR 样式自动提取;使用 createDOMRenderer 创建隔离渲染器,SSRProvider 生成确定性 ID 以匹配 hydration。
- Pages Router:在 _app.tsx 中配置 RendererProvider、SSRProvider 与 FluentProvider;在 _document.tsx 的 getInitialProps 中为每个请求创建新渲染器,并通过 renderToStyleElements 将样式注入文档 head。
- 介绍 fluentui-nextjs-appdir-plugin:在 webpack 编译期间自动为 @fluentui/* 与 @griffel/* 包入口添加 'use client' 指令,减少手动样板代码。
- 介绍 Griffel AOT(构建期 CSS 提取):通过 @griffel/webpack-extraction-plugin 与 @griffel/babel-preset 在构建时提取 CSS,消除运行时样式生成开销。
使用方式
App Router 流程:安装 @fluentui/react-components 与 @fluentui/react-icons;创建 app/providers.tsx 作为客户端边界,包裹 RendererProvider、SSRProvider、FluentProvider,并用 useServerInsertedHTML 注入样式;在 app/layout.tsx 中引入 Providers(layout 本身仍为服务端组件);使用 Fluent 组件的页面或组件文件需加 'use client'。数据获取放在服务端组件,再以 props 传给客户端 Fluent 组件。
Pages Router 流程:安装依赖;在 pages/_app.tsx 中配置 Provider 层级;在 pages/_document.tsx 的 getInitialProps 中创建每请求渲染器、增强 renderPage 传递 renderer,并调用 renderToStyleElements 注入样式。
插件方式:安装 fluentui-nextjs-appdir-plugin,在 next.config.js 或 next.config.mjs 中用 withFluentUI 包裹配置。
AOT 方式:安装 @griffel/webpack-extraction-plugin 与 @griffel/babel-preset,在 webpack 配置中加入 GriffelCSSExtractionPlugin 与对应 loader(evaluateStylesAtBuild: true);若使用 Babel,则在 .babelrc 中加入 @griffel/babel-preset。
适用场景
- 需要在 Next.js App Router 或 Pages Router 中集成 Fluent UI React v9 的项目。
- 希望避免 FOUC 与 hydration 不匹配、正确完成 SSR 样式注入的场景。
- 希望减少 'use client' 样板代码,或希望通过 AOT 提取 CSS 优化客户端包体积与性能的场景。
限制
- FluentProvider 必须位于客户端组件包装中,即使使用 appdir 插件也如此,因为它需要 useServerInsertedHTML 进行 SSR 样式注入。
- 使用 @griffel/babel-preset 会使 Next.js 从 SWC 回退到 Babel,速度较慢;基于 SWC 的配置应仅使用 webpack loader。
- 从 @fluentui/react-components 桶导出导入可能引入整个包,即使启用 tree shaking 也可能给客户端包增加 200+ KB(GitHub #33850)。
- Turbopack(next dev --turbo)与部分 Griffel 特性兼容性有限,Griffel AOT 提取在 Turbopack 下不工作(资料原文在此处截断)。
- 资料未提供具体收费、价格或平台支持信息。