Loaders are how webpack handles anything beyond plain JavaScript.
Out of the box webpack understands JavaScript and JSON. Loaders teach it other file types or transform code, configured in module.rules:
test: a regex matched against the file path, e.g./\.css$/i.use: one loader or an array of loaders (withoptionsobjects).exclude/include: limit which files a rule applies to, e.g.exclude: /node_modules/for Babel.
Loader chains run right to left (bottom to top). For CSS:
css-loaderresolves@importandurl()and turns CSS into a JavaScript module.style-loadertakes that result and injects it into the page via<style>tags.
So use: ["style-loader", "css-loader"] runs css-loader first. Add "sass-loader" at the end for Sass, or "postcss-loader" between them for autoprefixing.
Common loaders:
babel-loaderfor modern syntax and JSX; alternativesswc-loaderandesbuild-loaderare much faster.ts-loaderfor TypeScript, or Babel/SWC to strip types and runtsc --noEmitseparately.css-loaderwithmodules: true(or files named*.module.cssby default) for CSS modules.
Images and fonts no longer need loaders in webpack 5; they use asset modules (next lesson).
Example
// webpack.config.js
module.exports = {
mode: "development",
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"], // runs right to left
},
{
test: /\.m?jsx?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: { presets: [["@babel/preset-env", { targets: "defaults" }]] },
},
},
],
},
};
// src/index.js: import "./style.css"; -> styles injected at runtimeRemember
module.rules: test + use (+ include/exclude)- Loader chains execute right to left
- style-loader + css-loader for CSS; babel/swc/esbuild loaders for JS
- Exclude node_modules from expensive transforms
Watch out for
- Writing
["css-loader", "style-loader"], which feeds raw CSS to style-loader and fails.