I am doing a little bit of investigation about React and started to experiment with sass-loader for CSS/SCSS module handling. I've already most of the setup complete, but I got a problem that I'm not really sure how to tackle, and I present it in the following scenario:
ComponentA.jsx
import React from 'react';
import ComponentB from './app/components/ComponentB.jsx';
// Importing Core CSS module for component A
require("./ComponentA.scss");
export default class ComponentA extends React.Component{
constructor(){
...
}
render(){
return (
<div>
<ComponentB />
</div>
);
}
}
ComponentB.jsx
import React from 'react';
// Importing CSS module for component B with some overriding content for component A
require("./ComponentB.scss");
export default class ComponentB extends React.Component{
constructor(){
...
}
render(){
return (
...
);
}
}
webpack.config.js
var path = require("path");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
devServer: {
contentBase: path.join(__dirname, "../build")
},
entry: path.join(__dirname,"../app/ComponentA.jsx"),
module:{
loaders: [
{
test: /\.jsx?$/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
},
{
test: /\.(scss|css)$/,
loader: ExtractTextPlugin.extract(['css','sass'])
},
...
]
},
output: {
path: path.join(__dirname, "..", "build"),
filename: "bundle.js",
publicPath: "/"
},
plugins: [
new ExtractTextPlugin(
"style.css",
{ allChunks: true }
)
]
};
From this setup, Webpack worked as expected and created the new file style.css (virtually of course as I'm on development), BUT... the SCSS content files were not rendered in the order that I thought it would be.
The resulting style.css content was arranged as:
Instead of:
As I meant it to be on the hierarchy. This is a problem in the matter that as for overriding Component A base CSS I would need webpack and sass-loader to merge files in the hierarchy order.
So, after this the question would be:
How can I configure sass-loader to load the modules as it passes over the tree?
or even simpler...
Is there a better way to do this?
You need to think of components in React as self-contained entities even when it comes to stylesheets. It's not only about the JavaScript and JSX (or markup in general), but CSS (or SCSS) too.
That's why often the preferred approach is to use local CSS, together with the bare minimum of global styles. I suggest that you do the same in your case: move some of the styles in ComponentA and ComponentB in the global scope (you can think of it as critical CSS), and have local styles for each that override them.
The way to make styles local is to add the :local
prefix, perhaps wrapped in a container (i.e. ComponentA), like so:
:local(.ComponentA) {
background: red;
& > img{
width: 100%;
}
}
It's worth mentioning that this will transform your SCSS file into inline styles. In many cases, that can help with perceived performance and first paint.