I'm trying to configure webpack in such a way, that for a certain .css files it does not emit css(does not add anything to styles.css), but emits locals(className to style mapping in the imported object in js). In css-loader modules
option is always enabled (aka CSS Modules). For example:
In some .js file:
import cssNoEmit from './styles.noemit.scss'
import cssEmit from './styles.scss'
the contents of styles.noemit.scss:
.testNoEmit {
background: orange;
}
the contents of styles.scss:
.testEmit {
background: blue;
}
What i want to achieve is that the final generated .css contains .testEmit
class only. Also, both cssNoEmit
and cssEmit
contain mappings to a relevant classes in the generated .css
It may by possible to solve this with extract-text-plugin
, but i'm not looking for that solution, since this plugin is deprecated.
Here is what i have tried:
All the attempts have reproductible examples here
EDIT: attempts 1 (thanks to @felixmosh) and 5 managed to work.
Attempt 1 (working). css-loader has an option onlyLocals
. The description in the css-loader documentation is very vague, but as i understand it is supposed to do the exactly the same thing i am trying to achieve.
{
test: /\.noemit\.scss$/,
use: [
//MiniCssExtractPlugin.loader, // after disabling this, it started to work
{
loader: 'css-loader',
options: {
modules: {
mode: 'local',
exportGlobals: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
context: path.resolve(__dirname, 'src'),
hashPrefix: '_',
},
importLoaders: 2,
onlyLocals: true, // setting this to true causes transpilation to crash
},
},
...
],
},
Attempt 5 (working, not perfectly). Trying to use webpack built-in feature, SplitChunksPlugin. I tried to create a config for this use case based on this, SplitChinksPlugin docs, this, this.
...
optimization: {
splitChunks: {
cacheGroups: {
groupUnusedStyles: {
name: "unusedStyles",
chunks: "all",
test: /\.noemit\.scss$/,
enforce: true
},
}
}
}
This approach redirects unwanted css into unusedStyles.css
It works, with one small, but frustrating drawback. Apart from unusedStyles.css it generates unusedStyles.js and this has to be included in html, otherwise the app won't run.
To be more specific, both chunks have to be inside html:
<script type="text/javascript" src="/app.bundle.js"></script>
<script type="text/javascript" src="/unusedStyles.bundle.js"></script>
Does anyone know how to make it work without needing to add another bundle?
Attempt 2 (not working). Don't use onlyLocals
setting and ommit a loader that is responsible for the "css output"(such as style-loader
or mini-extract-css-plugin
). In this case the contents of imported css are very strange
Attempt 3 (not working) null-loader
does not work either, as it imports just an empty object
Attempt 4 (not working). There is another idea:
class ServerMiniCssExtractPlugin extends MiniCssExtractPlugin {
getCssChunkObject(mainChunk) {
return {};
}
}
... // use ServerMiniCssExtractPlugin the same way as MiniCssExtractPlugin
This does not work, because final .css has all the styles, as if normal MiniCssExtractPlugin was used
Also, there is a related thread on github.
Your first attempt is the correct one, just remove MiniCssExtractPlugin.loader
from the noemit.scss
loader list.
I've tried it locally, it works, the out css contains only the none "noemit" files but there is css-modules object mapping for both.
The removed loader (MiniCssExtractPlugin) is the one that responsible to include the scss in the final css file.