CSS Module processing in webpack provides local scoping for CSS through automatic class name transformation. This system parses CSS files, identifies local and global identifiers, creates dependencies for transformation, and generates both CSS output and JavaScript exports. This document covers the CssParser, CssModulesPlugin, CssModule class, dependency types, and code generation process.
CSS Module processing involves several specialized classes that handle parsing, dependency creation, and code generation.
Component Architecture Diagram
Sources: lib/css/CssModulesPlugin.js168-194 lib/css/CssParser.js296-314 lib/CssModule.js25-37 lib/css/CssGenerator.js44-56
The CssModulesPlugin registers CSS module types and integrates the parsing and generation pipeline with webpack's compilation process.
Module Type Registration
The plugin registers four CSS module types through NormalModuleFactory.hooks.createParser and NormalModuleFactory.hooks.createGenerator:
| Module Type | Default Mode | Auto-detection |
|---|---|---|
css | "pure" | No |
css/global | "global" | No |
css/module | "local" | No |
css/auto | "auto" | *.module.css via regex |
The auto-detection for css/auto type uses: IS_MODULES = /\.module(s)?\.[^.]+$/i
Sources: lib/css/CssModulesPlugin.js258-298 lib/css/CssParser.js59
Dependency Registration
The plugin registers dependency factories and templates during compilation setup:
Sources: lib/css/CssModulesPlugin.js210-257
CssModule Class Creation
The plugin implements NormalModuleFactory.hooks.createModuleClass to instantiate CssModule instead of NormalModule for CSS imports. This allows tracking of CSS-specific metadata like cssLayer, supports, media, and inheritance from parent CSS imports.
Sources: lib/css/CssModulesPlugin.js310-378 lib/CssModule.js25-37
The CssParser class extends the base Parser class and tokenizes CSS source code using walkCssTokens. It creates dependencies for local identifiers, imports, exports, and URL references.
Parser Initialization
The parser is instantiated with options controlling its behavior:
| Option | Type | Description |
|---|---|---|
defaultMode | "pure" | "global" | "local" | "auto" | Scoping mode for identifiers |
importOption | boolean | Whether to handle @import rules |
url | boolean | Whether to create dependencies for url() |
namedExports | boolean | Whether exports are named or default |
Sources: lib/css/CssParser.js300-314
Token Processing Pipeline
Sources: lib/css/CssParser.js340-390 lib/css/CssParser.js692-1270
Dependency Creation
The parser creates different dependency types based on context:
| Context | Dependency Type | Purpose |
|---|---|---|
| Local class/id | CssLocalIdentifierDependency | Transform to unique identifier |
| CSS variable | CssLocalIdentifierDependency | Transform --var-name |
| Animation name | CssSelfLocalIdentifierDependency | Reference to local keyframe |
@value export | CssIcssExportDependency | Export value to JS |
@value import | CssIcssImportDependency | Import value from other CSS |
| ICSS symbol | CssIcssSymbolDependency | Replace symbol with imported value |
@import | CssImportDependency | Import other CSS module |
url() | CssUrlDependency | Asset reference |
Sources: lib/css/CssParser.js631-638 lib/css/CssParser.js786-792 lib/css/CssParser.js1039-1044 lib/css/CssParser.js1013-1017 lib/css/CssParser.js925-933
The CssGenerator class extends the base Generator class and produces both CSS output (with transformed class names) and JavaScript export code.
Generator Configuration
Sources: lib/css/CssGenerator.js49-56
Code Generation Process
The generate() method produces different output depending on the generation type:
Sources: lib/css/CssGenerator.js76-194
Export Convention Handling
The generator uses cssExportConvention() to transform export names according to the configured convention:
| Convention | Input | Output |
|---|---|---|
"as-is" | "foo-bar" | ["foo-bar"] |
"camel-case" | "foo-bar" | ["foo-bar", "fooBar"] |
"camel-case-only" | "foo-bar" | ["fooBar"] |
"dashes" | "foo-bar" | ["foo-bar", "fooBar"] |
"dashes-only" | "foo-bar" | ["fooBar"] |
Sources: lib/util/conventions.js15-46 lib/dependencies/CssLocalIdentifierDependency.js106-112
The CssModule class extends NormalModule to add CSS-specific metadata needed for proper module identification and inheritance tracking.
CSS-Specific Properties
The inheritance property tracks nested CSS imports with their layer/supports/media context, enabling proper cascading of CSS conditions.
Sources: lib/CssModule.js17-37
Identifier Generation
The identifier() method creates a unique identifier that includes all CSS-specific metadata to ensure separate module instances for different import contexts:
identifier = super.identifier() +
"|" + cssLayer +
"|" + supports +
"|" + media +
"|inheritance_0|..." +
"|" + hot
Sources: lib/CssModule.js42-74
The parser tracks scoping mode using modeData variable and isLocalMode() helper function. When in local mode, identifiers are wrapped in dependencies for transformation.
Scope Detection Logic
The :local() and :global() pseudo-classes set modeData to override the default mode:
:local or :local() sets modeData = "local":global or :global() sets modeData = "global"modeData is reset at end of rule blockSources: lib/css/CssParser.js415-418 lib/css/CssParser.js1177-1263
Custom properties (CSS variables) starting with -- are transformed when in local mode:
--my-var → --_module_css-my-var
The @property at-rule for registering custom properties also transforms the property name:
Sources: lib/css/CssParser.js626-638 lib/css/CssParser.js1046-1062
The @value at-rule implements ICSS (Interoperable CSS) for importing/exporting values between CSS modules.
Export Syntax
Creates CssIcssExportDependency with name-value pairs. The entire @value rule is replaced with empty string via ConstDependency.
Import Syntax
Stores definitions in icssDefinitions Map for later symbol replacement. When identifiers matching imported values are encountered, creates CssIcssImportDependency or CssIcssSymbolDependency.
Sources: lib/css/CssParser.js936-1022 lib/dependencies/CssIcssExportDependency.js28-36 lib/dependencies/CssIcssImportDependency.js1-10
The parser handles @keyframes at-rules and animation properties:
Keyframe Name Transformation
When OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name) matches (e.g., @keyframes, @-webkit-keyframes), the keyframe name is transformed:
Animation Property Handling
When property name matches OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY (e.g., animation, animation-name, -webkit-animation), the parser sets inAnimationProperty = true and tracks identifiers for transformation via CssSelfLocalIdentifierDependency.
Sources: lib/css/CssParser.js1024-1045 lib/css/CssParser.js640-643 lib/css/CssParser.js649-665
The CssLocalIdentifierDependency.Template class transforms local identifiers using the getLocalIdent() function.
Transformation Algorithm
Sources: lib/dependencies/CssLocalIdentifierDependency.js41-80
Placeholder Substitution
The localIdentName pattern uses webpack's path templating system via compilation.getPath():
| Placeholder | Replacement |
|---|---|
[local] | Original identifier |
[name] | Module filename |
[folder] | Parent folder name |
[path] | Relative path from context |
[file] | Filename with extension |
[ext] | File extension |
[hash] | Hash of path and identifier |
[uniqueName] | output.uniqueName config |
[contenthash] | Hash digest |
Sources: lib/dependencies/CssLocalIdentifierDependency.js69-79
CSS module behavior is configured through parser and generator options when registering module types.
Parser Options (CssParserOptions)
| Option | Type | Default | Description |
|---|---|---|---|
importOption | boolean | true | Enable @import processing |
url | boolean | true | Enable url() processing |
defaultMode | "pure" | "global" | "local" | "auto" | "pure" | Default scoping mode |
namedExports | boolean | true | Use named exports |
Sources: lib/css/CssParser.js289-294 lib/css/CssParser.js300-310
Generator Options
| Option | Type | Default | Description |
|---|---|---|---|
exportsConvention | CssGeneratorExportsConvention | undefined | Name transformation |
localIdentName | string | "[uniqueName]-[id]-[local]" | Transformed name pattern |
exportsOnly | boolean | false | Skip CSS generation |
esModule | boolean | true | Use ES module syntax |
Sources: lib/css/CssGenerator.js49-54
Example Configuration
Sources: test/configCases/css/css-modules/webpack.config.js8-40
Sources: test/configCases/css/css-modules/use-style.js1-54
Sources: test/configCases/css/css-modules/use-style.js12-17 test/configCases/css/css-modules/style.module.css8-20
CSS Modules can be detected automatically by filename convention:
When using type: "css/auto":
*.module.css are treated as CSS modulesWhen using explicit types:
type: "css/module" - Always treated as CSS modulestype: "css/global" - Never treated as CSS modulesThe detection is done via a regular expression check:
Sources: lib/css/CssParser.js59 lib/css/CssParser.js352-357
CSS Modules generates two outputs:
The transformed class names typically follow this pattern:
_[filename]-[classname]
Sources: test/__snapshots__/ConfigTestCases.basictest.js.snap24-69 test/__snapshots__/ConfigTestCases.basictest.js.snap487-489
The transformation of CSS Modules involves several steps:
CssParser identifies local selectors and creates dependenciesCssLocalIdentifierDependency transforms local identifiers into unique namesCssIcssExportDependency creates the JavaScript exportsCssGenerator generates both the CSS output and the JavaScript mappingDuring build, webpack creates a dependency graph of these transformations and applies them when generating the output.
Sources: lib/css/CssParser.js336-421 lib/css/CssGenerator.js72-194 lib/dependencies/CssLocalIdentifierDependency.js182-245
When CSS Modules are used in a project, webpack automatically injects code for loading and handling the CSS at runtime. The CssLoadingRuntimeModule ensures CSS can be loaded dynamically and properly handled during Hot Module Replacement (HMR).
Sources: lib/css/CssModulesPlugin.js518-545 lib/css/CssLoadingRuntimeModule.js32-54
Refresh this wiki