Build plugins for XDS source builds. Provides babel, PostCSS, and Vite integrations that compile XDS library and product code with separate class name prefixes, which enables independent CSS layers:
reset < astryx-base (library, astryx prefix) < astryx-theme < product (app, x prefix)
StyleX generates atomic CSS: same declaration = same class name. Without separate prefixes, library and product classes collide and can't be placed in independent CSS layers, which breaks theme overrides.
@astryxdesign/build solves this by:
- Compiling XDS library code with
astryxprefix (.astryx78zum5) - Compiling product code with default
xprefix (.x78zum5) - Placing each group in its own CSS
@layer
| Export | Purpose | Platform |
|---|---|---|
@astryxdesign/build/babel |
Babel plugin: splits class prefixes per file | Next.js, any babel pipeline |
@astryxdesign/build/postcss |
PostCSS plugin: compiles + splits CSS layers | Next.js |
@astryxdesign/build/vite |
Vite plugin: wraps unplugin + splits layers | Vite, Storybook |
npm install -D @astryxdesign/build @stylexjs/babel-plugin @babel/coreFor Vite, also install:
npm install -D @stylexjs/unpluginconst path = require('path');
module.exports = {
presets: ['next/babel'],
plugins: [
[
'@astryxdesign/build/babel',
{
dev: process.env.NODE_ENV !== 'production',
runtimeInjection: false,
treeshakeCompensation: true,
enableInlinedConditionalMerge: true,
aliases: {
'@astryxdesign/core/*': [path.join(__dirname, 'node_modules/@astryxdesign/core/*')],
'@astryxdesign/core': [path.join(__dirname, 'node_modules/@astryxdesign/core')],
},
unstable_moduleResolution: {type: 'commonJS'},
},
],
],
};const path = require('path');
module.exports = {
plugins: {
'@astryxdesign/build/postcss': {
appDir: 'src',
babelPlugins: [
[
'@stylexjs/babel-plugin',
{
dev: process.env.NODE_ENV !== 'production',
runtimeInjection: false,
treeshakeCompensation: true,
enableInlinedConditionalMerge: true,
aliases: {
'@astryxdesign/core/*': [path.join(__dirname, 'node_modules/@astryxdesign/core/*')],
'@astryxdesign/core': [path.join(__dirname, 'node_modules/@astryxdesign/core')],
},
unstable_moduleResolution: {type: 'commonJS'},
},
],
],
},
},
};const nextConfig = {
transpilePackages: ['@astryxdesign/core', '@astryxdesign/theme-neutral'],
webpack: config => {
// Resolve to source TypeScript instead of dist
config.resolve.conditionNames = ['source', 'import', 'require', 'default'];
return config;
},
};
export default nextConfig;src/app/layers.css:
@layer reset, astryx-base, astryx-theme, product;src/app/globals.css:
@import './layers.css';
@import '@astryxdesign/core/reset.css';
@import '@astryxdesign/theme-neutral/theme.css';
@stylex;
layers.cssmust be a separate file because webpack hoists@importcontent above inline CSS.
{
"browserslist": ["last 1 Chrome version"]
}import {astryxStylex} from '@astryxdesign/build/vite';
import react from '@vitejs/plugin-react';
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: {
'@astryxdesign/core': path.resolve(__dirname, 'node_modules/@astryxdesign/core/src'),
},
},
optimizeDeps: {
exclude: ['@astryxdesign/core', '@astryxdesign/theme-neutral'],
},
});Wraps @stylexjs/babel-plugin with two internal instances: one with classNamePrefix: 'astryx' for library files, one with default 'x' for product files. Routes each file to the correct instance based on its path.
Library patterns (configurable):
packages/core/packages/themes/node_modules/@astryxdesign/
Compiles StyleX from both library and product source files in two separate passes with different prefixes. Wraps the results in named @layer blocks:
- Library rules →
@layer astryx-base - Product rules →
@layer product
Wraps @stylexjs/unplugin and intercepts the dev CSS endpoint (/virtual:stylex.css). Partitions the collected rules by file path and serves split-layer CSS.
[
'@astryxdesign/build/babel',
{
// Patterns to identify library files (default shown)
libraryPatterns: [
'packages/core/',
'packages/themes/',
'node_modules/@astryxdesign/',
],
// Class name prefix for library styles (default: 'astryx')
libraryPrefix: 'astryx',
// Class name prefix for product styles (default: 'x')
classNamePrefix: 'x',
// ... all @stylexjs/babel-plugin options
},
];'@astryxdesign/build/postcss': {
appDir: 'src', // Your app source directory
babelPlugins: [...], // StyleX babel plugin config
libraryPrefix: 'astryx', // Prefix for library CSS (default: 'astryx')
extraInclude: [...], // Additional glob patterns
layers: { // Layer names (defaults shown)
library: 'astryx-base',
product: 'product',
},
}- example-nextjs-source: full Next.js source build example
@stylexjs/babel-plugin: the underlying StyleX compiler