npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vite-css-modules

v1.6.0

Published

Vite plugin for correct CSS Modules behavior

Downloads

10,088

Readme

vite-css-modules

CSS Modules is currently broken in Vite. This Vite plugin fixes them by correctly handling CSS Modules.

Note: We're working to integrate this fix directly into Vite (PR #16018). Until then, use this plugin to benefit from these improvements now.

→ Play with a demo on StackBlitz

Why use this plugin?

Currently, CSS Modules is implemented incorrectly in Vite, leading to critical issues that makes it unusable. This plugin corrects the implementation, fixing many known bugs and making CSS Modules work expectedly in your projects.

Here are the issues this plugin addresses:

Dependency duplication

Prevents duplicated CSS Modules, preventing style conflicts from duplication and minimizing bundle size

Hot Module Replacement (HMR) issues

Enables HMR in CSS Module dependencies, improving development efficiency

Plugin compatibility

Allows other Vite plugins (e.g. PostCSS/SCSS) to process CSS Modules dependencies

Improved composition handling

This plugin raises errors for missing composes dependencies and supports CSS class names that collide with JavaScript reserved keywords.

Install

npm install -D vite-css-modules

Setup

In your Vite config file, add the patchCssModules() plugin to patch Vite's CSS Modules behavior:

// vite.config.js
import { patchCssModules } from 'vite-css-modules'

export default {
    plugins: [
        patchCssModules() // ← This is all you need to add!

        // Other plugins...
    ],
    css: {
        // Your existing CSS Modules configuration
        modules: {
            // ...
        },
        // Or if using LightningCSS
        lightningcss: {
            cssModules: {
                // ...
            }
        }
    },
    build: {
        // Recommended minimum target (See FAQ for more details)
        target: 'es2022'
    }
}

This patches your Vite to handle CSS Modules in a more predictable way.

Configuration

Configuring the CSS Modules behavior remains the same as before.

Read the Vite docs to learn more.

Bonus feature: strongly typed CSS Modules

This plugin can conveniently generate type definitions for CSS Modules by creating .d.ts files alongside the source files. For example, if style.module.css is imported, it will create a style.module.css.d.ts file next to it containing type definitions for the exported class names.

This improves the developer experience by providing type-safe class name imports, better autocompletion, and enhanced error checking directly in your editor when working with CSS Modules.

To enable this feature, pass generateSourceTypes to the patchCssModules plugin:

patchCssModules({
    generateSourceTypes: true
})

API

patchCssModules(options)

The patchCssModules function is the main method of the plugin and accepts an options object. Here are the options you can configure:

options.exportMode

  • Type: 'both' | 'named' | 'default'
  • Default: 'both'

Specifies how class names are exported from the CSS Module:

  • both: Exports class names as both named and default exports.
  • named: Exports class names as named exports only.
  • default: Exports class names as a default export only (an object where keys are class names).

options.generateSourceTypes

  • Type: boolean
  • Default: false

If enabled, this option generates TypeScript .d.ts files for each CSS module, providing type definitions for all exported class names. This feature enhances developer experience by enabling autocompletion and type safety for imported CSS classes.

FAQ

What issues does this plugin address?

Vite currently processes CSS Modules by bundling each entry point separately using postcss-modules. This approach leads to several significant problems:

  1. CSS Modules are not integrated into Vite's build process

    Since each CSS Module is bundled in isolation, Vite plugins cannot access the dependencies resolved within them. This limitation prevents further CSS post-processing by Vite plugins, such as those handling SCSS, PostCSS, or LightningCSS transformations. Even though postcss-modules attempts to apply other PostCSS plugins to dependencies, it encounters issues, as reported in Issue #10079 and Issue #10340.

  2. Duplicated CSS Module dependencies

    Because each CSS Module is bundled separately, shared dependencies across modules are duplicated in the final Vite build. This duplication results in larger bundle sizes and can disrupt your styles by overriding previously declared classes. This problem is documented in Issue #7504 and Issue #15683.

  3. Silent failures on unresolved dependencies

    Vite (specifically, postcss-modules) fails silently when it cannot resolve a composes dependency. This means missing exports do not trigger errors, making it harder to catch CSS bugs early. This issue is highlighted in Issue #16075.

By addressing these issues, the vite-css-modules plugin enhances the way Vite handles CSS Modules, integrating them seamlessly into the build process and resolving these critical problems.

How does this work?

The plugin changes Vite's handling of CSS Modules by treating them as JavaScript modules. Here's how it achieves this:

  • Transformation into JavaScript modules

    CSS Modules are inherently CSS files that export class names through a JavaScript interface. The plugin compiles each CSS Module into a JavaScript module that loads the CSS. In this process, composes statements within the CSS are transformed into JavaScript imports, and the class names are exported as JavaScript exports.

  • Integration into Vite's module graph

    By converting CSS Modules into JavaScript modules, they become part of Vite's module graph. This integration allows Vite (and Rollup) to efficiently resolve, bundle, and de-duplicate CSS Modules and their dependencies.

  • Enhanced plugin compatibility

    Since CSS Modules are now part of the module graph, other Vite plugins can access and process them. This resolves issues where plugins were previously unable to process dependencies within CSS Modules.

This approach mirrors how Webpack’s css-loader works, making it familiar to developers transitioning from Webpack. Additionally, because this method reduces the overhead in loading CSS Modules, it can offer performance improvements in larger applications.

Does it export class names as named exports?

Yes, the plugin allows class names to be exported as named exports, but there are some considerations:

  • JavaScript variable naming limitations

    In older versions of JavaScript, variable names cannot include certain characters like hyphens (-). Therefore, class names like .foo-bar couldn't be directly exported as foo-bar because it's not a valid variable name. Instead, these class names were accessible through the default export object.

  • Using localsConvention

    To work around this limitation, you could use the css.modules.localsConvention: 'camelCase' option in Vite's configuration. This setting converts kebab-case class names to camelCase (e.g., foo-bar becomes fooBar), allowing them to be used as valid named exports.

  • ES2022 and arbitrary module namespace identifiers

    With the introduction of ES2022, JavaScript now supports arbitrary module namespace identifier names. This feature allows you to export and import names with any characters, including hyphens, by enclosing them in quotes. This means class names like .foo-bar can be directly exported as named exports.

To use this feature, set your Vite build target to es2022 or above in your vite.config.js:

{
    build: {
        target: 'es2022'
    }
}

You can then import class names with special characters using the following syntax:

import { 'foo-bar' as fooBar } from './styles.module.css'

This approach lets you access all class names as named exports, even those with characters that were previously invalid in JavaScript variable names.

Sponsors