Skip to main content

Next.js

Learn how to configure Next.js to use React Strict DOM.

About Next.js

Next.js is a production-grade, full-stack, web-only React framework that is fully compatible with React Strict DOM. The instructions in the rest of this guide are tailored to Next.js, but can be adapted by readers to work with other frameworks.

Follow the Next.js instructions on how to create a new project. Then follow the steps in the Installation guide to install React Strict DOM.

Babel configuration

Babel is not the default compiler when using Next.js App Router, but it can still be used. Create or modify a babelLoader.config.js (not babel.config.js) file as follows. This is used to optimize builds and enables static extraction of CSS for web. Learn how to configure the babel-preset in the API docs.

babelLoader.config.js
const dev = process.env.NODE_ENV !== 'production'

const config = {
cacheDirectory: true,
parserOpts: {
plugins: ['typescript', 'jsx'],
},
presets: [
[
'react-strict-dom/babel-preset',
{
debug: dev,
dev,
platform: 'web',
rootDir: process.cwd(),
},
],
],
};

export default config;

PostCSS configuration

PostCSS is a tool for generating CSS. It's enabled by default in Next.js and it's the recommended way to extract React Strict DOM styles to static CSS for web builds. react-strict-dom/postcss-plugin can be used to extract styles. Create a postcss.config.mjs file as follows.

postcss.config.mjs
// Be sure to share the babel configuration between Next.js and PostCS
import babelLoader from "./babelLoader.config.js";

const config = {
plugins: {
"react-strict-dom/postcss-plugin": {
include: [
// Include source files to watch for style changes
'src/**/*.{js,jsx,mjs,ts,tsx}',
// List any installed node_modules that include UI built with React Strict DOM
'node_modules/<package-name>/*.js'
],
babelConfig: babelLoader,
useLayers: true,
},
autoprefixer: {},
},
};

export default config;

Next.js configuration

Create or edit the next.config.js file as follows. Note that below you will find config for both turbopack or webpack.

next.config.js
import type { NextConfig } from "next";

import babelLoader from "./babelLoader.config.js";

function getBabelLoader() {
return {
loader: "babel-loader",
options: babelLoader,
};
}

const nextConfig: NextConfig = {
transpilePackages: ["react-strict-dom"],

turbopack: {
rules: {
"*.{js,jsx,ts,tsx}": {
loaders: [getBabelLoader()],
},
},
},

webpack: (config, { webpack }) => {
config.resolve.mainFields = ["module", "main"];
config.module.rules.push({
exclude: /node_modules(?!\/react-strict-dom)/,
test: /\.(js|jsx|ts|tsx)$/,
use: [getBabelLoader()],
});
return config;
},
};

export default nextConfig;

App files

Your app needs to include a CSS file that contains a @stylex directive. This acts as a placeholder that is replaced by the generated CSS during builds.

stylex.css
/* This directive is used by the react-strict-dom postcss plugin. */
/* It is automatically replaced with generated CSS during builds. */
@stylex;

Next, import the CSS file in the layout.tsx file.

src/app/layout.tsx
// Required for CSS to work on Next.js
import './stylex.css';

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}

Platform-specific files

React Strict DOM relies on platform-specific extensions to create platform-specific implementations of components, hooks, etc. For example, web bundles should package *.web.js file extensions but not *.native.js files. Next.js can handle the presence of platform-specific extensions with a change in next.config.js with the following additions:

next.config.js
const webOnlyExtensions = ['.web.js', '.web.jsx', '.web.ts', '.web.tsx'];

const nextConfig: NextConfig = {
// ...
turbopack: {
// ...
resolveExtensions: [ ...webOnlyExtensions, ".tsx", ".ts", ".jsx", ".js", ".mjs", ".json"],
},
webpack: (config, { webpack }) => {
// ...
config.resolve.extensions = [ ...webOnlyExtensions, ...config.resolve.extensions];
return config;
},
};

export default nextConfig;