Skip to content

Vite Plugin

Enhance your Vite development experience with HMR and style validation

Vite Plugin

The optional @typestyles/vite plugin enhances your development experience with Hot Module Replacement (HMR) and helpful warnings.

Installation

bash
npm install -D @typestyles/vite
# or
pnpm add -D @typestyles/vite
# or
yarn add -D @typestyles/vite

Basic setup

Add the plugin to your vite.config.ts:

ts
import { defineConfig } from 'vite';
import typestyles from '@typestyles/vite';

export default defineConfig({
  plugins: [typestyles()],
});

Features

Hot Module Replacement (HMR)

Without the plugin, editing a style file causes a full page reload. With the plugin:

  • Style changes apply instantly
  • Component state is preserved
  • No flicker or re-render cascade

The plugin works by:

  1. Detecting when a module uses typestyles
  2. Injecting HMR accept handlers
  3. Invalidating affected style registrations on file change
  4. Triggering a targeted update instead of a full reload

Duplicate namespace warnings

The plugin warns you when multiple files use the same namespace:

Style namespace "button" is also used in /path/to/other/file.ts.
Duplicate namespaces cause class name collisions.

This helps catch issues early, since duplicate namespaces can cause unexpected style overwrites.

Configuration

Disable duplicate warnings

If you have a legitimate use case for duplicate namespaces (uncommon), you can disable the warning:

ts
import { defineConfig } from 'vite';
import typestyles from '@typestyles/vite';

export default defineConfig({
  plugins: [
    typestyles({
      warnDuplicates: false,
    }),
  ],
});

How HMR works

When you save a file that imports from typestyles, the plugin:

  1. Extracts namespaces: Parses your code to find all styles.create(), tokens.create(), createTheme(), and keyframes.create() calls

  2. Injects HMR code: Adds Vite's import.meta.hot handlers to the module

  3. On file change:

    • The HMR handler calls invalidateKeys() from typestyles/hmr
    • Affected styles are removed from the internal registry
    • The module re-executes with fresh style definitions
    • New CSS is injected, replacing the old rules
  4. State preserved: React/Vue/Svelte components keep their state since only the module containing styles changed

Example: seeing HMR in action

Create a simple Vite app with typestyles:

ts
// src/tokens.ts
import { tokens } from 'typestyles';

export const color = tokens.create('color', {
  primary: '#0066ff',
});

// src/styles.ts
import { styles } from 'typestyles';
import { color } from './tokens';

export const button = styles.create('button', {
  base: {
    backgroundColor: color.primary,
    padding: '8px 16px',
  },
});

// src/main.ts
import { button } from './styles';

document.getElementById('app').innerHTML = `
  <button class="${button('base')}">Click me</button>
`;

Run the dev server:

bash
npm run dev

Now edit src/tokens.ts and change the primary color. The button updates instantly without a page reload!

Framework integration

The plugin works with any Vite-based framework:

React

bash
npm create vite@latest my-app -- --template react-ts
npm install typestyles @typestyles/vite
ts
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import typestyles from '@typestyles/vite';

export default defineConfig({
  plugins: [react(), typestyles()],
});

Vue

bash
npm create vite@latest my-app -- --template vue-ts
npm install typestyles @typestyles/vite
ts
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import typestyles from '@typestyles/vite';

export default defineConfig({
  plugins: [vue(), typestyles()],
});

Svelte

bash
npm create vite@latest my-app -- --template svelte-ts
npm install typestyles @typestyles/vite
ts
// vite.config.ts
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import typestyles from '@typestyles/vite';

export default defineConfig({
  plugins: [svelte(), typestyles()],
});

SSR with Vite

The plugin is development-only and doesn't affect SSR. For SSR, use collectStyles() from typestyles/server as described in the SSR guide.

Troubleshooting

HMR not working

  1. Check that the plugin is listed in vite.config.ts
  2. Ensure your files import from 'typestyles' (not a relative path to the package)
  3. Verify import.meta.hot is available (dev mode, not production)

Duplicate namespace warnings appearing incorrectly

The detection is regex-based and may have false positives if you:

  • Have strings that look like typestyles calls in comments
  • Use variable names like styles for other purposes

These are rare and don't affect functionality—just ignore the warning or disable it.

Full reloads still happening

Some changes require a full reload:

  • Adding/removing imports that affect the module graph
  • Changes to non-typestyles code in the same file
  • Type-only changes (TypeScript types don't affect runtime)

Plugin performance

The plugin adds minimal overhead:

  • Only transforms files that import from 'typestyles'
  • Transformation is a simple regex match, not a full AST parse
  • No runtime code is added in production builds

Is the plugin required?

No. TypeStyles works perfectly without it. The plugin is purely a development convenience for:

  • Faster iteration with HMR
  • Early warning about duplicate namespaces

If you prefer full page reloads or use a different bundler, you don't need this plugin.

Future features

Planned enhancements (not yet implemented):

  • Dead style detection: Warn when styles are defined but never used
  • Build-time extraction: Optionally extract static styles to CSS files for production
  • Source maps: Map generated CSS back to your style definitions

Stay tuned to the GitHub repository for updates.

Last updated Apr 2, 2026 Edit this page