Skip to main content

StyleX with Vite

@stylexjs/unplugin integrates directly with Vite to compile StyleX code, aggregate the generated CSS, and append it to the CSS assets Vite emits. How you load the CSS/runtime in development depends on whether your entry point is an HTML file or a React (JS/TS) module.

Installation

Start by installing the StyleX unplugin package:

npm install --save-dev @stylexjs/unplugin

Configuration

Add the plugin to your Vite configuration and provider the StyleX configuration options.

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import stylex from '@stylexjs/unplugin';

export default defineConfig({
plugins: [
stylex.vite({
// StyleX configuration options
useCSSLayers: true,
dev: process.env.NODE_ENV === 'development',
runtimeInjection: false,
// ...
lightningcssOptions: {
// Options for lightningcss which postprocesses the generated CSS
}
}),
react()
],
});

CSS entrypoint

In almost all cases, it is useful to have at least one CSS file that is imported by a component that is part of every route, such as the root layout component. The StyleX unplugin package's vite plugin will inject the generated CSS in the existing CSS asset.

This CSS file is also a good place for any CSS resets or global styles that you may want.

Dev-server and Hot Reloading

If your Vite setup uses an HTML file as the entry point, you should not need any further build setup. However, if your entry point is a React component, you may need to load some virtual modules to enable hot reloading.

We recommend encapsulating this in a special client component file like this:

// src/app/DevStyleXInject.tsx
'use client';

import { useEffect } from 'react';

function DevStyleXInjectImpl() {
useEffect(() => {
if (import.meta.env.DEV) {
// @ts-ignore
import('virtual:stylex:css-only');
}
}, []);
return <link rel="stylesheet" href="/virtual:stylex.css" />;
}

export function DevStyleXInject({ cssHref }: { cssHref: string }) {
return import.meta.env.DEV ? (
<DevStyleXInjectImpl />
) : (
<link rel="stylesheet" href={cssHref} />
);
}

The dynamic import is wrapped in an additional check for import.meta.env.DEV to ensure that it is not bundled in production.

And then, this component can be used in the <head> section of your document layout component:

// src/app/Document.tsx (excerpt)
import { DevStyleXInject } from './DevStyleXInject';

export function Layout({ children }: { children: React.ReactNode }) {
return (
<html>
<head>
{/* ... */}
<DevStyleXInject cssHref="/stylex.css" />
{/* ... */}
</head>

<body>
<div id="root">{children}</div>
</body>
</html>
)
);

The virtual:stylex.css file will load the generated CSS, and the virtual:stylex:runtime file will refetch it on every HTML event to enable hot reloading.

Framework-specific guides

Documentation for specific Vite-based setups and frameworks is provided in the following pages, along with smaller framework-specific details for each.