Vite and asset delivery
Vite produces two different manifests. The asset collector reads
public/_ to find built CSS and JavaScript.
StyleX Connector reads the site's stylex- to turn semantic
keys into class names. Build and deploy both outputs together.
Install build packages
Use the project's existing package manager. With npm at the project root:
npm install @stylexjs/stylex
npm install --save-dev vite vite-plugin-typo3 @stylexjs/unplugin @babel/parser
@babel/ is needed by the optional maintained manifest adapter. Install a
Node.js release supported by the Vite version selected for your project.
Declare an entrypoint
vite- reads the installed sitepackage's
Configuration/. Paths in that file are relative to
the JSON file:
["../Resources/Private/JavaScript/Main.entry.js"]
The entrypoint must import every StyleX source file whose keys Fluid uses. Start with explicit imports. For many custom Content Blocks, see Content Blocks for glob discovery.
import '../CSS/main.css';
import './Stylex/Button.stylex.js';
import './main.js';
Compile StyleX and write its manifest
Add @stylexjs/ and the maintained static manifest adapter to
vite.. The adapter accepts an options object. Its
output must match the PHP registration in Connect the build to TYPO3. The
connector ships it at Resources/.
Prebuilt-manifest consumers do not need Node.js at PHP runtime.
import { defineConfig } from 'vite';
import typo3 from 'vite-plugin-typo3';
import stylexPlugin from '@stylexjs/unplugin';
import stylexManifestPlugin from './vendor/skom/stylex-connector/Resources/Private/Build/stylex-manifest.mjs';
export default defineConfig({
plugins: [
typo3(),
stylexPlugin.vite({
useCSSLayers: false,
unstable_moduleResolution: {
type: 'commonJS',
rootDir: process.cwd(),
},
}),
stylexManifestPlugin({
outputPath: 'packages/my_sitepackage/Resources/Public/StylexManifest/stylex-manifest.json',
}),
],
});
use suits sites that load unlayered CSS, including a
typical Bootstrap or Fluid Styled Content setup. For layered CSS, read
Bootstrap and cascade layers before changing the option.
The adapter supports static compiled conflict maps from *.,
*., *. and *.. Run Vite from the
Composer project root, where the build dependencies are installed. Its tests
pin StyleX 0.19.1. Dynamic functions and other unsupported conflict values
fail the build. Use a separate consumer adapter to generate complete recipes.
The canonical key includes namespace, root-relative module path, style object
and variant, for example site/.
Set root to the source package and namespace to its stable package name
for shorter keys. Real paths remove Composer symlink differences.
legacy defaults to true, adding Button. for existing Fluid
templates. Ambiguous aliases and duplicate keys fail instead of silently
replacing entries. Disable aliases after migrating templates. include
accepts a regular expression or predicate for other source naming policies.
compiler records your pinned compiler version.
The adapter replaces each module's entries after a successful transform, removes deleted modules, and resets collection for each production build. Production publication runs after bundle writing. It hashes emitted CSS and writes a deterministic v2 manifest with an atomic temporary-file replacement. A failed transform or build leaves the previous manifest intact. Build into a staging directory: atomic JSON replacement does not make separately written CSS atomic. See Upgrade and deploy builds for deployment and rollback.
Import a nonempty CSS file from the entrypoint. StyleX 0.19.1 attaches its CSS to an existing Vite CSS asset, so an entrypoint without that import can leave its fallback CSS outside the Vite manifest's entrypoint references.
For a first style, create Button. beside the other StyleX
sources and import it in Main.:
import * as stylex from '@stylexjs/stylex';
export const styles = stylex.create({
root: { padding: '0.75rem 1rem', backgroundColor: 'rebeccapurple' },
});
Development CSS and production assets
TYPO3 renders the document, so Vite does not inject StyleX's virtual CSS
through transform. Add this once to the JavaScript entrypoint
to load it from the Vite origin during development:
if (import.meta.env.DEV) {
const linkId = '__stylex_dev_css__';
let link = document.getElementById(linkId);
if (!link) {
link = document.createElement('link');
link.id = linkId;
link.rel = 'stylesheet';
document.head.appendChild(link);
}
const cssUrl = `${new URL(import.meta.url).origin}/virtual:stylex.css`;
link.href = cssUrl;
const refresh = () => { link.href = `${cssUrl}?t=${Date.now()}`; };
import.meta.hot?.on('stylex:css-update', refresh);
import.meta.hot?.on('vite:afterUpdate', refresh);
}
In production, Vite emits physical CSS. The asset collector includes it through the built entrypoint. Do not also enable the connector's TypoScript CSS include for that same file. Next, connect these outputs to TYPO3 in Connect the build to TYPO3.