I am trying to make a React app themeable. For now themes only consist of different sets of Sass variables which define different header colors, etc.
From my current understanding the ExtractTextPlugin
seems to be my best bet as I don't want my styles to be inlined and rather have separate files per theme.
So I created two themes:
src/scss/themes/theme-a.scss
src/scss/themes/theme-b.scss
The themes import the basic layout and common styles and override the relevant variables.
But the only way I managed to make webpack create separate css files
for both themes was to create distinct entry points for each theme in
my webpack.prod.config
:
entry: {
app: './src/js/init.js',
theme-a: './src/scss/themes/theme-a.scss',
theme-b: './src/scss/themes/theme-b.scss'
},
But adding a new entry point for every new theme that gets added feels wrong and I figure there must be a better way?
To avoid having to manually add the themes one possible solution is to create a function that reads contents of the themes folder and programatically add an entry for each *.scss file.
Something along the lines of this:
function getThemes(themePath) {
var themes = {};
fs.readdirSync(themePath).forEach(function(fileName) {
var fileNameWithPath = path.join(themePath, fileName);
var stat = fs.lstatSync(fileNameWithPath);
if (stat.isDirectory()) return;
if (!/\.scss$/.test(fileName)) return;
var nameWithoutExt = path.basename(fileName, '.scss');
themes[nameWithoutExt] = fileNameWithPath;
});
return themes;
}
var themes = getThemes('./src/scss/themes');
var config= {
entry: _.merge({ app: './src/js/init.js' }, themes),
// rest of options
};
This will require you to restart your dev-server or re-run you webpack build when adding new theme files though, but at least you won't have to touch your webpack config.
Here's your solution:
npm i --save-dev file-loader
In the loaders
section, add this:
{
test: /themes\/.+\.scss$/,
loader: "file-loader?name=./compiled-themes/css/[name].css!css!sass"
},
There may be more scss files, if so there must be another section which bundles them as usual, but skips the themes:
{
test: /\.scss$/,
exclude: /themes\/.+\.scss$/,
loader: "css!sass"
},
The file loader writes files by filename, hash and extension so you are able to preserve the name.
Note the name=./compiled-themes/css/[name].css
part, where []
vars are substituted.
https://github.com/webpack/file-loader
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