I want to bundle multiple scss and js entries into multiple output files using webpack.
I have tried different solutions for it, but non of them did what I needed.
This is how the directory structure looks like:
assets
package.json
webpack.config.js
css
dist
src
lib
pages
fonts.scss
main.scss
js
dist
lib
src
components
pages
App.js
I want to end up having the main.scss & all the scss files from the "css/src/pages" directory compiled to "css/dist/main.css" and "css/dist/pages/page-name.css".
My webpack.config.js file looks like this:
const path = require('path');
const fs = require('fs');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
let config = {
mode: "production",
watch: true,
module: {
rules: [
{
test: /.scss$/i,
include: [
path.resolve(__dirname, 'css/src'),
path.resolve(__dirname, 'css/src/pages')
],
// use: [MiniCssExtractPlugin.loader, "css-loader", 'sass-loader']
// use: ['file-loader', 'sass-loader', 'css-loader']
use: [
{
loader : 'file-loader',
options: { outputPath: '/', name: '[name].css'}
},
'sass-loader'
]
}
]
},
// plugins: [new MiniCssExtractPlugin()],
// optimization: {
// minimize: true,
// minimizer: [new CssMinimizerPlugin()]
// }
};
const main = Object.assign({}, config, {
name: 'main',
entry: './js/src/App.js',
output: {
filename: 'app.min.js',
path: path.resolve(__dirname, 'js/dist'),
}
});
const exp = [main];
const jsDir = __dirname + "\js\src\pages";
const jsFiles = fs.readdirSync(jsDir);
jsFiles.forEach(fileName => {
const nameOnly = fileName.replace(".js", "");
const current = Object.assign({}, config, {
name: nameOnly,
entry: './js/src/pages/'+fileName,
output: {
filename: fileName,
path: path.resolve(__dirname, 'js/dist/pages'),
}
});
exp.push(current);
});
// const cssMain = Object.assign({}, config, {
// name: 'mainCss',
// entry: './css/src/main.scss',
// output: {
// filename: 'main.css',
// path: path.resolve(__dirname, 'css/dist'),
// }
// });
// exp.push(cssMain);
const cssDir = __dirname + "\css\src\pages";
const cssFiles = fs.readdirSync(cssDir);
cssFiles.forEach(fileName => {
const nameOnly = fileName.replace(".scss", "");
const current = Object.assign({}, config, {
name: nameOnly + "Css",
entry: './css/src/pages/'+fileName,
output: {
filename: nameOnly + ".css",
path: path.resolve(__dirname, 'css/dist/pages'),
}
});
exp.push(current);
});
module.exports = exp;
As you can see there are few lines that are commented out, those are part of the things I’ve tried, but non of it worked, unfortunately.
The scss files from the "css/src/pages" directory always print javascript inside like in the attached screenshot and the main.scss file is compiled well into css but not into the right directory (it goes to "css/dist/pages" too).
FYI – the javascript compilation works as expected.
Any help will be highly appreciated! Thank you in advance 🙂
2
Answers
After many hours spent on this issue, I found the solution that I was looking for.
I'm adding here my new webpack.config.js file, in case someone will come across this type of issue too:
And this is the package.json file:
Hope it'll help someone :)
Firstly, note that the
file-loader
you’re currently using processes the import/requires on a file, then emits the file into the output directory. However, this is not exactly what you need for processing SCSS/SASS files. Instead, you should use theMiniCssExtractPlugin
which extracts CSS into separate files. It creates a CSS file per JS file which contains CSS.Here’s a way you could structure your webpack.config.js file to achieve what you’re looking for:
In this setup,
getEntries
is a helper function that gets all files with the provided extension from the provided directory and prepares the entries object for Webpack. For the SCSS config, it is specifying separate output paths for the main.scss and the other SCSS files in the ‘pages’ directory. This way, the main.css will be directly under the ‘dist’ directory, and the others under the ‘pages’ directory.You also might want to consider adding Babel loader for transpiling JavaScript files and setting it up in Webpack.
Remember to install all the necessary dependencies via npm. You may also need to create ‘.babelrc’ for Babel setup and configure Babel for your JavaScript files as per your project requirements.
For the error screenshot you provided, it seems like the output is trying to interpret CSS as JS, which happens if you’re not correctly setting up
MiniCssExtractPlugin
. Make sure you’re using it correctly, as shown in the provided configuration.