I'm starting to work with Webpack 2 and I saw that a lot of projects are using the css-loader and I didn't find what is the purpose for it.
EDIT: In original answer I was describing style-loader
not css-loader
. It's easy to forget different purpose of those loader since css-loader
can only be used with style-loader
.
css-loader
gives you more control over importing .css
files.
1. Transforms url(image.png) => require('./image.png')
Since now require
is used, it's enables you to use for example file-loader
or url-loader
.
Now url(image.png)
can be converted to:
url(/public-path/0dcbbaa701328a3c262cfd45869e351f.png)
or with limit property of url-loader
creates inline picture:
url(data:image/jpeg;base64,LzlqLzRBQ ... zdF3)
2. Enables CSS Modules
Let's consider styles of componentA
and componentB
:
componentA/style.css
.wrapper {
background-color: blue;
}
.specificToComponentA {
// rest of styles
}
componentB/style.css
.wrapper {
background-color: red;
}
.specificToComponentB {
// rest of styles
}
componentA
looks:
import './style.css';
export default function () {
document.body.innerHTML = `
<div class="wrapper">
<div class="specificToComponentA">componentA</div>
</div>
`;
}
and componentB
looks:
import './style.css';
export default function () {
document.body.innerHTML = `
<div class="wrapper">
<div class="specificToComponentB">componentB</div>
</div>
`;
}
What color of background color those components would have? This problem is related with leaking of styles, it's hard to tell if they are will be red or blue (it's hard to predict order of styles created by style-loader
). If you use CSS Modules approach you can deal with this problem.
Now import styles to variable and this variable will contain object with mapping class names:
componentA
with CSS Modules looks:
import s from './style.css';
export default function () {
document.body.innerHTML = `
<div class="${s.wrapper}">
<div class="${s.specificToComponentA}">componentA</div>
</div>
`;
}
s
object will contain :
{
wrapper: "WO0HHIhH77",
specificToComponentA: "jPYPsVTDZu"
}
componentA/style.css
will be converted to
.WO0HHIhH77 {
background-color: blue;
}
.jPYPsVTDZu {
// rest of styles
}
and componentB
with CSS Modules looks:
import s from './style.css';
export default function () {
document.body.innerHTML = `
<div class="${s.wrapper}">
<div class="${s.specificToComponentB}">componentB</div>
</div>
`;
}
s
object will contain :
{
wrapper: "C8EKTwiZfd", // Look, different than in componentA!!!
specificToComponentB: "KI5jRsC2R5"
}
componentB/style.css
will be converted to
.C8EKTwiZfd { // Look, different than in componentA!!!
background-color: red;
}
.KI5jRsC2R5 {
// rest of styles
}
And now even if you don't use super specific name like wrapper
in both components you are sure that they don't overlap and componentA
stays blue and componentB
red. It's great power of encapsulation of styles described as CSS Modules - it is possible with help of css-loader
.
Let's consider this structure of project
├── components
│ │
│ ├── componentA
│ │ ├── style.css
│ │ └── index.js
│ │
│ ├── componentB
│ │ ├── style.css
│ │ └── index.js
│ │
│ └── componentC
│ ├── style.css
│ └── index.js
│
├── index.js
└── index.html
index.js
looks like this
import componentA from './components/componentA';
import componentB from './components/componentB';
import componentC from './components/componentC';
componentA();
componentB();
componentC();
1. Without css-loader style-loader
each of *.js
components in general looks like this
export default function () {
// logic of this component
}
index.html
contains
<link href="components/componentA/style.css" rel="stylesheet" type="text/css">
<link href="components/componentB/style.css" rel="stylesheet" type="text/css">
<link href="components/componentC/style.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="dist/bundle.js"></script>
Now if you want to refactor your code and for example disable componentB
you must remove it from index.js
import componentA from './components/componentA';
// import componentB from './components/componentB';
import componentC from './components/componentC';
componentA();
// componentB();
componentC();
and since css and js are decoupled you must do the same for styles in index.html
<link href="components/componentA/style.css" rel="stylesheet" type="text/css">
<!-- <link href="components/componentB/style.css" rel="stylesheet" type="text/css"> -->
<link href="components/componentC/style.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="dist/bundle.js"></script>
This duplication in large project can lead to leaving dead css code - it's harder to maintain since you must do two things in separate places.
NOTE: SASS or LESS have the same problem. It's only moved from index.html
to index.sass
:
@import './components/componentA';
@import './components/componentB'; // you must disable this manually
@import './components/componentC';
2. With css-loader style-loader
Now you point to styles related to some component directly from it (not in separate place like in 1. point)
For example your *.js
component will look like
import './style.css';
export default function () {
// logic of this component
}
and index.html
<script type="text/javascript" src="dist/bundle.js"></script>
The most important is that if you have this architecture and want to disable componentB
, only what you do is
import componentA from './components/componentA';
// import componentB from './components/componentB';
import componentC from './components/componentC';
componentA();
// componentB();
componentC();
It's all! No more looking for reference of styles componentB/style.css
in any .html
or .sass
or .less
. The same goes if you want to add new components: by simply importing .js
file you add js logic and css styles. This is much easier to maintain!
In .js
file ES6 import
or CommonJS's require()
allows you to import only JavaScript files(modules) into it. So when you include your styles.css
, for instance, in .js
file via import from './styles.css'
, you'll need to convert in into .js
in the first place. And here is where css-loader comes to the rescue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With