Usage with Vite
Installation
Since Vite supports Rollup plugin Since Vite provides more features and flexibility, WyW-in-JS has a separate plugin for it @wyw-in-js/vite. Vite handles CSS by itself, you don't need a css plugin.
# npm
npm i -D @wyw-in-js/vite
# yarn
yarn add --dev @wyw-in-js/vite
# pnpm
pnpm add -D @wyw-in-js/vite
# bun
bun add -d @wyw-in-js/viteConfiguration
import { defineConfig } from 'vite';
import wyw from '@wyw-in-js/vite';
export default defineConfig(() => ({
// ...
plugins: [wyw()],
}));import.meta.env during evaluation
WyW-in-JS evaluates a subset of your code at build time to extract styles. When that code relies on Vite's import.meta.env.*,
the Vite plugin injects Vite env values into the evaluation context so the expressions behave like they do in Vite runtime.
The injected object is available as __wyw_import_meta_env and includes:
- Vite's
MODE,BASE_URL,DEV,PROD,SSR - variables loaded via
loadEnv()respectingenvPrefix(by defaultVITE_)
If you need to override values, you can provide your own overrideContext option and set __wyw_import_meta_env explicitly.
SSR dev FOUC (styles after hydration)
When using Vite SSR in dev mode (middlewareMode + ssrLoadModule), the server-rendered HTML may not include the
generated WyW CSS. The page then renders unstyled until the client runtime loads the CSS after hydration (FOUC).
To avoid this, enable ssrDevCss to make the plugin:
- collect generated CSS in memory,
- expose it as a virtual stylesheet (
/_wyw-in-js/ssr.cssby default), - inject
<link rel="stylesheet">viatransformIndexHtml().
export default defineConfig(() => ({
// ...
plugins: [wyw({ ssrDevCss: true }), react()],
}));You can customize the URL via ssrDevCssPath:
plugins: [wyw({ ssrDevCss: true, ssrDevCssPath: '/_wyw-in-js/ssr.css' }), react()],This is dev-only and does not change production builds.
Notes:
- The served stylesheet is the raw WyW output (before Vite's CSS pipeline), so some edge cases like
url(...)rewriting may behave differently. - The
<link>tag is injected on each HTML transform; CSS HMR does not “re-inject” the link on the client without a page reload (which is fine for avoiding initial FOUC).
Keeping CSS comments
Stylis strips CSS comments by default. To preserve them (for example, /*rtl:ignore*/), pass keepComments:
export default defineConfig(() => ({
// ...
plugins: [wyw({ keepComments: true })],
}));Vite also strips CSS comments during build minification by default. To keep them in the final output, disable CSS minification:
export default defineConfig(() => ({
// ...
build: { cssMinify: false },
plugins: [wyw({ keepComments: true })],
}));If you are using language features that requires a babel transform (such as typescript), ensure the proper babel presets or plugins are passed to wyw.
import { defineConfig } from 'vite';
import wyw from '@wyw-in-js/vite';
// example to support typescript syntax:
export default defineConfig(() => ({
// ...
plugins: [
wyw({
include: ['**/*.{ts,tsx}'],
babelOptions: {
presets: ['@babel/preset-typescript', '@babel/preset-react'],
},
}),
],
}));