@stylexswc/nextjs-plugin
Version:
StyleX plugin for Next.js powered by a Rust NAPI-RS/SWC compiler. Supports Webpack, Rspack, and Turbopack builds with CSS extraction.
405 lines (319 loc) • 10.9 kB
Markdown
> StyleX plugin for Next.js, powered by a Rust compiler (NAPI-RS + SWC).
> Supports Webpack, Rspack, and Turbopack builds. Part of the
> [StyleX SWC Plugin](https://github.com/Dwlad90/stylex-swc-plugin#readme)
> workspace.
This plugin integrates [StyleX](https://stylexjs.com) into Next.js using
[`@stylexswc/rs-compiler`](https://www.npmjs.com/package/@stylexswc/rs-compiler),
a Rust implementation of the StyleX transform, instead of the official Babel
plugin. That means you keep Next.js's fast SWC toolchain — no `.babelrc`, no
Babel fallback — and your StyleX code stays exactly the same. Per-file
transforms are 2x to 5x faster than with Babel — see
[performance](https://github.com/Dwlad90/stylex-swc-plugin#performance).
This is a community project and is not affiliated with Meta. It tracks the
official StyleX releases
<!-- stylex-compatibility:start -->(currently compatible with StyleX v0.19.0)<!-- stylex-compatibility:end -->,
requires Node.js 20 or newer, and supports Next.js 15+ (App Router and Pages
Router).
## Installation
```bash
npm install --save-dev @stylexswc/nextjs-plugin
```
Your application still needs the StyleX runtime:
```bash
npm install @stylexjs/stylex
```
## Usage
The plugin supports all three Next.js bundlers. Pick the export that matches
your setup.
### Using with Webpack
For standard Next.js Webpack builds, use the default import:
```js
// next.config.js
const stylexPlugin = require('@stylexswc/nextjs-plugin');
module.exports = stylexPlugin({
// StyleX options here
})({
// Next.js config here
});
```
For Next.js with [Rspack](https://rspack.rs), use the `/rspack` export. It
applies the experimental
[`next-rspack`](https://www.npmjs.com/package/next-rspack) adapter for you — no
manual `withRspack` composition needed:
```ts
import stylexPlugin from '@stylexswc/nextjs-plugin/rspack';
module.exports = stylexPlugin({
// StyleX options here
})({
// Next.js config here
});
```
> [!NOTE]
> Run `next dev` and `next build` without the `--webpack`/`--turbopack`
> flags. For `next start`, set `NEXT_RSPACK=true` in the environment (the
> production server only serves prebuilt output, but it still evaluates the
> config).
The Rspack integration extracts StyleX CSS from both Server and Client
Components, with the same options as the Webpack plugin, plus `stylexPackages`
from
[`@stylexswc/rspack-plugin`](https://github.com/Dwlad90/stylex-swc-plugin/tree/develop/packages/rspack-plugin).
> [!NOTE]
> Packages listed in `transpilePackages` are automatically added to the
> `stylexPackages` allowlist, so StyleX source shipped in `node_modules` (e.g.
> `@stylexjs/open-props`) is picked up without extra configuration.
### Using with Turbopack
> [!IMPORTANT]
> Turbopack does not support webpack plugins
> ([see Next.js docs](https://nextjs.org/docs/app/api-reference/turbopack#webpack-plugins)).
> When using Turbopack, the loader only compiles StyleX code but does not
> extract CSS.
>
> You must configure the PostCSS plugin for CSS extraction. Install
> `@stylexswc/postcss-plugin` and configure it in `postcss.config.js`:
>
> ```js
> // postcss.config.js
> module.exports = {
> plugins: {
> '@stylexswc/postcss-plugin': {
> rsOptions: {
> dev: process.env.NODE_ENV === 'development',
> },
> },
> autoprefixer: {},
> },
> };
> ```
For Next.js with Turbopack, use the `/turbopack` export:
```ts
import withStylexTurbopack from '@stylexswc/nextjs-plugin/turbopack';
export default withStylexTurbopack({
// StyleX options here, same as postcss-plugin
rsOptions: {
dev: process.env.NODE_ENV === 'development',
},
})({
// Next.js config here
});
```
> [!NOTE]
> When using Turbopack, the following options are not supported and will
> be ignored:
>
> - `useCSSLayers`
> - `nextjsMode`
> - `transformCss`
> - `extractCSS`
- Type: `Partial<StyleXOptions>`
- Optional
- Description: StyleX compiler options passed to `@stylexswc/rs-compiler`. For
the standard options, see the
[](https://stylexjs.com/docs/api/configuration/babel-plugin/).
> [!NOTE]
> The `include` and `exclude` options are exclusive to the Rust compiler
> and are not available in the official StyleX Babel plugin.
- Type: `(string | RegExp)[]`
- Optional
- Description: Glob patterns or regular expressions selecting the files to
transform. When specified, only files matching at least one pattern are
transformed. Patterns are matched against paths relative to the current
working directory.
- Type: `(string | RegExp)[]`
- Optional
- Description: Glob patterns or regular expressions excluding files from the
transform. A file matching any exclude pattern is skipped even if it matches
an `include` pattern. Patterns are matched against paths relative to the
current working directory.
- Type: `Array<string | { as: string, from: string }>`
- Default: `['stylex', '@stylexjs/stylex']`
- Description: Specifies where StyleX is imported from. Supports both string
paths and import aliases.
- Type: `UseLayersType`
- Default: `false`
- Description: Wraps the generated CSS in cascade layers for better style
isolation.
- Type: `boolean`
- Optional
- Default: `true`
- Description: Controls whether the generated CSS is extracted into a separate
file. Set to `false` when `@stylexswc/postcss-plugin` owns extraction.
- Type:
`(css: string, filePath: string | undefined) => string | Buffer | Promise<string | Buffer>`
- Optional
- Description: Custom CSS post-processing. The plugin injects CSS after all
loaders have run, so use this to apply PostCSS or other CSS transformations.
```js
const path = require('path');
const stylexPlugin = require('@stylexswc/nextjs-plugin');
const rootDir = __dirname;
module.exports = stylexPlugin({
rsOptions: {
dev: process.env.NODE_ENV !== 'production',
// Include only specific directories
include: [
'app/**/*.{ts,tsx}',
'components/**/*.{ts,tsx}',
'src/**/*.{ts,tsx}',
],
// Exclude test files and API routes
exclude: ['**/*.test.*', '**/*.stories.*', '**/__tests__/**', 'app/api/**'],
aliases: {
'@/*': [path.join(rootDir, '*')],
},
unstable_moduleResolution: {
type: 'commonJS',
},
},
stylexImports: ['@stylexjs/stylex', { from: './theme', as: 'tokens' }],
useCSSLayers: true,
transformCss: async (css, filePath) => {
const postcss = require('postcss');
const result = await postcss([require('autoprefixer')]).process(css, {
from: filePath,
map: {
inline: false,
annotation: false,
},
});
return result.css;
},
})({
transpilePackages: ['@stylexjs/open-props'],
// Optionally, add any other Next.js config below
});
```
```ts
import path from 'path';
import withStylexTurbopack from '@stylexswc/nextjs-plugin/turbopack';
const rootDir = __dirname;
export default withStylexTurbopack({
rsOptions: {
dev: process.env.NODE_ENV !== 'production',
aliases: {
'@/*': [path.join(rootDir, '*')],
},
unstable_moduleResolution: {
type: 'commonJS',
},
},
stylexImports: ['@stylexjs/stylex'],
})({
transpilePackages: ['@stylexjs/open-props'],
// Optionally, add any other Next.js config below
});
```
Required PostCSS configuration for CSS extraction under Turbopack:
```js
// postcss.config.js
const path = require('path');
module.exports = {
plugins: {
'@stylexswc/postcss-plugin': {
include: ['app/**/*.{js,jsx,ts,tsx}', 'components/**/*.{js,jsx,ts,tsx}'],
rsOptions: {
aliases: {
'@/*': [path.join(__dirname, '*')],
},
unstable_moduleResolution: {
type: 'commonJS',
},
dev: process.env.NODE_ENV === 'development',
},
},
autoprefixer: {},
},
};
```
Include only specific directories:
```js
stylexPlugin({
rsOptions: {
include: ['app/**/*.tsx', 'components/**/*.tsx'],
},
});
```
Exclude test files and API routes:
```js
stylexPlugin({
rsOptions: {
exclude: ['**/*.test.*', '**/*.stories.*', '**/__tests__/**', 'app/api/**'],
},
});
```
Using regular expressions (exclude always takes precedence over include):
```js
stylexPlugin({
rsOptions: {
include: [/app\/.*\.tsx$/, /components\/.*\.tsx$/],
exclude: [/\.test\./, /\.stories\./],
},
});
```
Exclude `node_modules` except specific packages (negative lookahead):
```js
stylexPlugin({
rsOptions: {
exclude: [/node_modules(?!\/@stylexjs\/open-props)/],
},
});
```
Transform only specific packages from `node_modules`:
```js
stylexPlugin({
rsOptions: {
include: [
'app/**/*.{ts,tsx}',
'components/**/*.{ts,tsx}',
'node_modules/@stylexjs/open-props/**/*.js',
'node_modules/@my-org/design-system/**/*.js',
],
exclude: ['**/*.test.*', 'app/api/**'],
},
});
```
Webpack (the default export) is the most battle-tested path and supports every
option. Turbopack gives the fastest dev server but needs the PostCSS plugin for
CSS extraction. Rspack is experimental in Next.js itself but works end to end
through the `/rspack` export.
No — that is the point of this plugin. StyleX is compiled by the Rust compiler
inside the SWC pipeline, so Next.js never falls back to Babel.
Add the package to `transpilePackages` in your Next.js config. It is then
transpiled by Next.js and automatically allowlisted for the StyleX transform.
Yes. Styles are extracted at build time from both Server and Client Components
into static CSS, so there is no runtime cost either way.
No. It is a community-maintained alternative to the official tooling and is not
affiliated with or supported by Meta.
- [Example repo](https://github.com/Dwlad90/nextjs-app-dir-stylex)
- [CodeSandbox with example repo](https://codesandbox.io/p/github/Dwlad90/nextjs-app-dir-stylex/main)
- [StyleX documentation](https://stylexjs.com)
- [`@stylexswc/rs-compiler` compiler options](https://github.com/Dwlad90/stylex-swc-plugin/tree/develop/crates/stylex-rs-compiler)
This plugin was inspired by
[`stylex-webpack`](https://github.com/SukkaW/stylex-webpack).
MIT — see
[](https://github.com/Dwlad90/stylex-swc-plugin/blob/develop/LICENSE)