Site icon FSIBLOG

How to Fix the Webpack CSS Module Error Getting My Styles to Load

How to Fix the Webpack CSS Module Error Getting My Styles to Load

How to Fix the Webpack CSS Module Error Getting My Styles to Load

Below is the original configuration you posted, the exact error message, why it happens, and a step-by-step fix. I’ll finish with a “practice” section that lets you try out a few extra Webpack tricks (CSS Modules, Sass, Autoprefixer, and Hot Reload) so you can see how each piece slots in.

Original Code

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const NodemonPlugin = require('nodemon-webpack-plugin');
require('file-loader');

module.exports = {
mode: process.env.NODE_ENV || 'production',
entry: './src/index.js',
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/i,
use: ['file-loader'],
},
{
test: /\.css$/i,
use: ['style-loader'], // ← only one loader here
}
]
},
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin(),
new NodemonPlugin()
]
};

Error as seen in the console

ERROR in ./src/component/list-view/list-view.css 1:3
Module parse failed: Unexpected token (1:3)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
> h2 {
| color: #ff0000;
| }

What Actually Broke

I had added only style-loader. That loader’s entire job is to inject a string of CSS into the <head> at runtime.
What it doesn’t do is turn a real .css file into that string. That’s css-loader’s territory.

Webpack applies loaders right to left (last loader runs first). So the correct stack is:

{
test: /\.css$/i,
use: ['style-loader', 'css-loader'] // css-loader on the right!
}

One npm i -D css-loader, one save, and the build finally compiled.

Breathing Room:

A green build was nice, but I wanted more:

That led me to the “practice playground” below.

Extra Dev Dependencies

i -D css-loader style-loader            \
mini-css-extract-plugin \
sass sass-loader \
postcss postcss-loader autoprefixer\
webpack-dev-server

The Playground Config

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
mode: process.env.NODE_ENV || 'development',
entry: './src/index.js',
devtool: 'source-map',

devServer: {
static: path.resolve(__dirname, 'dist'),
port: 3000,
hot: true,
open: true
},

module: {
rules: [
/* Images & fonts */
{ test: /\.(png|jpe?g|gif|svg|woff2?|eot|ttf|otf)$/i, type: 'asset/resource' },

/* Global CSS */
{
test: /\.css$/i,
exclude: /\.module\.css$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: { postcssOptions: { plugins: ['autoprefixer'] } }
}
]
},

/* CSS Modules */
{
test: /\.module\.css$/i,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { modules: true } }
]
},

/* Sass */
{
test: /\.s[ac]ss$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
}
]
},

output: {
filename: 'main.[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
},

plugins: [
new HtmlWebpackPlugin({ template: './public/index.html' }),
new MiniCssExtractPlugin({ filename: 'styles.[contenthash].css' })
]
};

What Each Upgrade Gives Me

FeatureWhy I Like It
MiniCssExtractPluginEmits a real styles.css so the browser can cache it and show styles immediately.
Source mapsWhen something breaks, DevTools points at the real file, not main.js.
Dev server + HMRSave a file, see the page refresh or even swap modules instantly.
asset/resourceCopies images and fonts to /dist without the old file-loader.
CSS ModulesI can write .title {} in two components and they’ll never clash.
SassVariables, nesting, and math right in my stylesheets.
AutoprefixerVendor prefixes appear (or don’t) based on my browserslist targets.

Quick Drills to Lock It In

styles from './list-view.module.css';
document.body.innerHTML = `<h2 class="${styles.title}">Hello Modules</h2>`;

Final Thoughts

That single missing loader taught me more about Webpack’s loader chain than any tutorial. Once I understood that every asset travels through a pipe of loaders, right-to-left, the whole ecosystem clicked:

Now my build spits out a clean main.[hash].js and styles.[hash].css, hot-reloads every time I hit save, and my component styles stay safely scoped in their own little worlds. Most important, I know why each piece is there—so the next error message feels like a puzzle, not a brick wall.

Exit mobile version