How Does Webpack Use Loaders in Asset Compilation?

Webpack relies on loaders as module-level preprocessors that translate non-JavaScript assets into valid modules ready for the dependency graph. During asset compilation, Webpack resolves dependencies, matches source files against defined module rules, executes loader pipelines across distinct pitching and normal execution phases, and finally passes standard JavaScript or asset structures to its internal parser.

Resolution and Rule Matching

Asset compilation begins when Webpack traces an import statement from an entry point or intermediate module. By default, Webpack natively understands standard JavaScript and JSON. When it encounters other file formats—such as TypeScript, SCSS, or static SVGs—it consults the module.rules array declared in the configuration.

Each rule typically defines a regular expression in the test property and an array of transformers in the use field. Webpack matches the file’s absolute path against these conditions. Once a match is confirmed, Webpack resolves the necessary loader packages from node_modules and constructs an execution pipeline specifically tailored to that resource.

The Two-Phase Pipeline: Pitching vs. Normal

Loaders do not simply execute linearly; they operate in two distinct stages known as the pitching phase and the normal phase.

Loader Pipeline: [Loader A, Loader B, Loader C]

1. Pitch Phase (Left-to-Right)
   Loader A.pitch() -> Loader B.pitch() -> Loader C.pitch()
                                                 |
                                         Fetch raw resource
                                                 |
2. Normal Phase (Right-to-Left)
   Loader A()       <- Loader B()       <- Loader C()
  1. The Pitching Phase (Left to Right): Execution traverses forward through the loader chain. If a loader exports a pitch method, Webpack executes it before reading the target file. If a pitch method returns a defined value, Webpack immediately short-circuits the pipeline, skipping the remaining pitch methods, bypassing reading the resource from disk, and passing that returned value directly to the previous loader's normal phase. This mechanism is crucial for caching, metadata inspection, and loaders like style-loader that inject inline runtime scripts without reading raw source code directly through the rest of the chain.
  2. The Normal Phase (Right to Left / Bottom to Top): If no loader short-circuits during the pitch stage, Webpack reads the target file from the filesystem into memory as a string or Buffer. The loader chain then executes in reverse. The first loader in this phase (the last listed in configuration) receives the raw file contents, transforms it, and returns the modified result. Each preceding loader takes the output of its predecessor as input, progressively compiling the asset.

Concrete Transformation: An SCSS Pipeline

Consider a standard style pipeline configured as use: ['style-loader', 'css-loader', 'sass-loader']:

  • sass-loader executes first in the normal phase, turning raw SCSS syntax into standard CSS text.
  • css-loader accepts the resulting CSS string and resolves @import rules, local url paths, and CSS Module mappings into CommonJS/ES module syntax.
  • style-loader wraps that output into runtime JavaScript code that creates `