How to Set Up Vite with @astryxdesign/build for StyleX Source Builds
The @astryxdesign/build Vite plugin wraps @stylexjs/unplugin to compile source-level StyleX with separate CSS layers for the Astryx design system (astryx prefix) and your product code (x prefix), enabling collision-free theming and injection control.
Setting up Vite with @astryxdesign/build for StyleX source builds lets you compile the Astryx design system directly from TypeScript source alongside your own components. This approach creates a clean separation between library styles and product styles using distinct CSS @layer blocks and class-name prefixes. The Vite plugin in @astryxdesign/build/vite handles all Babel configuration internally, making integration straightforward.
Install the Required Packages
Begin by installing the core build plugin and the official StyleX unplugin. According to the install section in the README, both packages are required for the Vite integration:
npm install -D @astryxdesign/build @stylexjs/unplugin
Configure the Vite Plugin
Import astryxStylex from @astryxdesign/build/vite and spread its return value into your plugins array. The plugin must appear before the React plugin so that StyleX's virtual CSS is generated prior to HMR handling, as documented in the Vite Setup code in the README.
The astryxStylex function accepts a stylexOptions object that mirrors the standard StyleX configuration:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { astryxStylex } from '@astryxdesign/build/vite';
import path from 'node:path';
export default defineConfig({
plugins: [
...astryxStylex({
stylexOptions: {
dev: process.env.NODE_ENV === 'development',
runtimeInjection: false,
treeshakeCompensation: true,
unstable_moduleResolution: { type: 'commonJS', rootDir: __dirname },
},
}),
react(),
],
resolve: {
alias: {
// Resolve the Astryx core source so Vite compiles it from TS
'@astryxdesign/core': path.resolve(__dirname, 'node_modules/@astryxdesign/core/src'),
},
},
optimizeDeps: {
// Prevent Vite from pre-bundling the source version of the library
exclude: ['@astryxdesign/core', '@astryxdesign/theme-neutral'],
},
});
The resolve.alias configuration is essential when using source builds—it directs Vite to compile Astryx from its TypeScript source rather than using pre-built artifacts.
Set Up CSS Layer Ordering
Create a layers.css file that defines the cascade order for your generated styles. This step, shown in the layers example in the README, ensures predictable style precedence:
/* src/app/layers.css */
@layer reset, astryx-base, astryx-theme, product;
The astryx-base and astyx-theme layers contain the Astryx design system styles with the astryx prefix, while the product layer holds your application styles with the default x prefix.
Import Layers and Trigger StyleX Processing
Reference your layers file and Astryx's bundled CSS in your global stylesheet, then add the @stylex; directive to trigger StyleX processing:
/* src/app/globals.css */
@import './layers.css';
@import '@astryxdesign/core/reset.css';
@import '@astryxdesign/theme-neutral/theme.css';
@stylex;
The @stylex; directive signals the plugin to inject the generated CSS at that location in the output.
Minimal Working Configuration
For a quick start, the repository's example Vite app demonstrates a minimal valid configuration:
// apps/example-vite/vite.config.ts
import {defineConfig} from 'vite';
import react from '@vitejs/plugin-react';
import {astryxStylex} from '@astryxdesign/build/vite';
import path from 'node:path';
export default defineConfig({
plugins: [...astryxStylex(), react()],
resolve: {
alias: {
'@astryxdesign/core': path.resolve(__dirname, 'node_modules/@astryxdesign/core/src'),
},
},
});
This configuration matches lines 4 and 8 of the source file, omitting explicit stylexOptions to use sensible defaults.
How the Plugin Works Internally
The source-level compilation pipeline relies on several key mechanisms implemented in [packages/build/src/vite.ts](https://github.com/facebook/astryx/blob/main/packages/build/src/vite.ts):
- Prefix separation: The Astryx library receives the
astryxclass-name prefix; product code keeps the defaultxprefix - Layer partitioning: The plugin intercepts the virtual StyleX CSS endpoint and splits generated rules by file path into separate
@layerblocks - Babel injection: Required Babel transforms are applied automatically without manual configuration
This architecture prevents class-name collisions between the design system and application code while enabling independent theming and CSS injection strategies.
What Each Configuration Option Controls
| Option | Purpose |
|---|---|
dev |
Enables development-mode transforms and debugging |
runtimeInjection |
When false, emits static CSS files instead of runtime-injected styles |
treeshakeCompensation |
Preserves styles for components that may be tree-shaken in production |
unstable_moduleResolution |
Resolves StyleX imports relative to the project root |
Summary
- Install
@astryxdesign/buildand@stylexjs/unpluginas dev dependencies - Add
astryxStylex()to your Vite plugins array before the React plugin - Configure
resolve.aliasto point@astryxdesign/coreat its TypeScript source - Exclude Astryx packages from
optimizeDepsto prevent pre-bundling issues - Define CSS layer order in a dedicated file and import Astryx's reset and theme CSS
- Use
@stylex;in your global stylesheet to trigger CSS generation
Frequently Asked Questions
What is the difference between using @astryxdesign/build and the standard @stylexjs/unplugin directly?
@astryxdesign/build wraps @stylexjs/unplugin to add automatic layer partitioning and prefix separation specifically for the Astryx design system. Without this wrapper, you would need to manually configure Babel transforms and implement your own logic to separate library styles from product styles. The plugin handles the astryx prefix assignment and @layer splitting based on file path patterns.
Why must the Astryx packages be excluded from optimizeDeps?
The optimizeDeps.exclude configuration prevents Vite from pre-bundling the source versions of @astryxdesign/core and its theme packages. Pre-bundling would transpile these packages to JavaScript and cache them, bypassing the source-level StyleX compilation that enables the prefix and layer separation. Keeping them as excluded allows Vite to process their TypeScript source through the full plugin pipeline on each build.
Can I customize the class-name prefix or layer names?
The astryx prefix and astryx-base/astryx-theme layer names are hardcoded in the current implementation in [packages/build/src/vite.ts](https://github.com/facebook/astryx/blob/main/packages/build/src/vite.ts). The plugin identifies Astryx source files by their path within node_modules/@astryxdesign/ and applies these conventions automatically. Customizing them would require modifying the plugin source or forking the repository.
What happens if I place the react() plugin before astryxStylex()?
Placing react() before astryxStylex() can cause HMR issues because the React plugin may process file changes before StyleX has generated its virtual CSS. The virtual CSS endpoint must be populated before HMR handlers run to ensure consistent style updates during development. The Vite Setup documentation explicitly recommends the plugin order shown in the configuration examples.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →