Server side rendering and browserless testing
For basic instructions on getting Next.js set up, see https://nextjs.org/
- Get a basic next.js setup running, rendering a page from the
pages
folder, as guided by the tutorial. - Add a dependency on
@fluentui/react
yarn add @fluentui/react
- Create a
_document.js
file under yourpages
folder with the following content:
import * as React from 'react';
import Document, { Head, Html, Main, NextScript } from 'next/document';
import { Stylesheet, resetIds } from '@fluentui/react';
// Fluent UI React (Fabric) 7 or earlier
// import { Stylesheet, resetIds } from 'office-ui-fabric-react';
const stylesheet = Stylesheet.getInstance();
// Now set up the document, and just reset the stylesheet.
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
resetIds();
const page = renderPage(App => props => <App {...props} />);
return { ...page, styleTags: stylesheet.getRules(true), serializedStylesheet: stylesheet.serialize() };
}
render() {
return (
<Html>
<Head>
<style type="text/css" dangerouslySetInnerHTML={{ __html: this.props.styleTags }} />
<!--
This is one example on how to pass the data.
The main purpose is to set the config before the Stylesheet gets initialised on the client.
Use whatever method works best for your setup to achieve that.
-->
<script type="text/javascript" dangerouslySetInnerHTML={{ __html: `
window.FabricConfig = window.FabricConfig || {};
window.FabricConfig.serializedStylesheet = ${this.props.serializedStylesheet};
` }} />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
- You should now be able to server render Fluent UI React components in any of your pages:
import * as React from 'react';
import {
Checkbox,
ColorPicker,
createTheme,
Dropdown,
ThemeProvider, // NOTE: Use Fabric instead in version 7 or earlier
initializeIcons,
PrimaryButton,
Slider,
TextField,
Toggle
} from '@fluentui/react';
initializeIcons();
const Index = () => (
<ThemeProvider>
<div>
<PrimaryButton>Hello, world</PrimaryButton>
<Toggle defaultChecked label="Hello" />
<TextField defaultValue="hello" />
<Dropdown disabled />
<Checkbox defaultChecked label="Hello" />
<Slider defaultValue={50} max={100} />
<ColorPicker />
</div>
</ThemeProvider>
);
export default Index;
Note: There are many steps missing below to get nodemon/babel/typescript/es modules working in a node.js environment. This will need to be elaborated on.
It's possible to render Fluent UI React components on the server side in a Node environment, using the SSR support in merge-styles
.
See https://codesandbox.io/s/dazzling-montalcini-kv9bz for an example which uses the SSR support to build html/css strings to inject into the page. The result is not mounted, so behaviors will not work, but represents the html/css output that would be generated by SSR.
Example:
import * as React from 'react';
import * as ReactDOM from 'react-dom/server';
import {
ThemeProvider // NOTE: Use Fabric instead in version 7 or earlier
// ...
} from '@fluentui/react';
import { renderStatic } from '@fluentui/merge-styles/lib/server';
// Fluent UI React (Fabric) 7 or earlier
// import { renderStatic } from '@uifabric/merge-styles/lib/server';
import './styles.css';
initializeIcons();
function App() {
return <ThemeProvider>...content goes here...</ThemeProvider>;
}
const serverRenderExample = () => {
const { html, css } = renderStatic(() => ReactDOM.renderToString(<App />));
// Use the html and css string content to inject into the response
};
serverRenderExample();
In unit or end-to-end tests that run in an SSR-like (non-browser) environment such as Node, you'll need to disable style loading.
const {
initializeIcons,
setRTL,
setResponsiveMode,
ResponsiveMode
} = require('@fluentui/react');
const themeLoader = require('@microsoft/load-themed-styles');
initializeIcons('dist/');
// Configure load-themed-styles to avoid registering styles.
themeLoader.configureLoadStyles(styles => {
// noop
});
// Set rtl to false.
setRTL(false);
// Assume a large screen.
setResponsiveMode(ResponsiveMode.large);
You'll also want to mock out requiring .scss
files. In Jest:
moduleNameMapper: {
// jest-style-mock.js should just contain module.exports = {};
'\\.(scss)$': path.resolve(__dirname, 'jest-style-mock.js'),
}
Some of our legacy styling was done through scss rather than merge-styles. Keeping legacy info here in case there are still scenarios which need to pipe load-themed-styles based styling into a server response.
The basic idea is to tell the styles loader to store styles in a variable, which you can later inject into your page. Example:
import { configureLoadStyles } from '@microsoft/load-themed-styles';
// Store registered styles in a variable used later for injection.
let _allStyles = '';
// Push styles into variables for injecting later.
configureLoadStyles((styles: string) => {
_allStyles += styles;
});
import * as React from 'react';
import * as ReactDOMServer from 'react-dom/server';
import { Text } from '@fluentui/react';
let body = ReactDOMServer.renderToString(<Text>hello</Text>);
console.log(
`
<html>
<head>
<style>${_allStyles}</style>
</head>
<body>
${body}
</body>
</html>
`
);
- FAQ - Fabric and Stardust to Fluent UI
-
@fluentui/react
Version 9 -
@fluentui/react
Version 8 - Contributing to the
7.0
branch - How to apply themes (version 7/8)
- Planning and development process (for work by the core team)
- Conducting meetings Style guide
- Keeping up with review requests
- RFC review process
- Setup (configuring your environment)
- Fluent UI React version 7/8
- CLA
- Overview
- Repo structure
- Development process
- Contributing to previous versions
- API Extractor
- Build command changes made in early 2020
- Component implementation guide
- Creating a component
- Implementation Best Practices
- Theming
- Documenting
- Styling (old approach)
- Overview
- Testing with Jest
- E2E testing (Cypress)
- Visual testing (Screener)
- Accessibility review checklist