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 astryx class-name prefix; product code keeps the default x prefix
  • Layer partitioning: The plugin intercepts the virtual StyleX CSS endpoint and splits generated rules by file path into separate @layer blocks
  • 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/build and @stylexjs/unplugin as dev dependencies
  • Add astryxStylex() to your Vite plugins array before the React plugin
  • Configure resolve.alias to point @astryxdesign/core at its TypeScript source
  • Exclude Astryx packages from optimizeDeps to 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →