I am working on a project that needs CSS and JavaScript code to be compiled in distinct files.
I have a JavaScript source file - <root>/src/js/main.js
- that is compiled into <root>/dist/main.js
, as expected.
The webpack config file looks like so:
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var path = require("path");
module.exports = {
mode: 'development',
entry: "./src/js/main.js",
output: {
path: path.resolve(__dirname, "dist/js"),
filename: '[name].js',
publicPath: "/dist"
},
watch:true,
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
]
}
In <root>/src/scss/
I have an app.scss
file with various imports:
// Fonts
@import url('https://fonts.googleapis.com/css?family=Nunito');
// Bootstrap 4
@import '~bootstrap/scss/bootstrap';
// Layout
@import './layout';
The directories and files tree:
The package.json
file:
{
"name": "myproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/preset-env": "^7.16.11",
"mini-css-extract-plugin": "^2.6.0",
"node-sass": "^7.0.1",
"sass": "^1.50.0",
"sass-loader": "^12.6.0",
"webpack": "^5.72.0",
"webpack-cli": "^4.9.2"
},
"dependencies": {
"@babel/core": "^7.17.9",
"babel-loader": "^8.2.4",
"bootstrap": "^4.6.0",
"css-loader": "^6.7.1",
"jquery": "^3.6.0",
"popper.js": "^1.16.1",
"style-loader": "^3.3.1"
}
}
The problem:
I need the SCSS to be compiled into <root>/dist/css/app.css
, but something must be missing from the webpack.config.js
file because no CSS file is generated.
Questions:
- What is missing from the config file?
- How can I make sure the generated CSS is minified?
CodePudding user response:
css bundling
Basically your css is not bundled cause webpack is configruated to build only ./src/js/main.js
file and all the other files that are imported from that single entry point.
To make webpack bundle css files you can either import it from handled js files or include it as additional entryPoint
into webpack.config.js
:
Option 1. Add import
Just add into src/js/main.js
file the following line
import "../scss/app.scss";
Option 2. Specify entry point in webpack config
Remove current entry point line
entry: "./src/js/main.js",
And add new entry point line with multiple entry points specified
entry: ["./src/js/main.js", "./src/scss/app.scss"],
output files structure
In your question you mentioned that you want to put js bundle to ./dist/js/main.js
and css bundle to ./dist/css/app.css
but webpack is not very flexible with multiple entry points output paths. So it's better to update your webpack config output field to the following one:
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].js",
publicPath: "/dist",
},
That will produce flat bundled chunks files structure like ./dist/main.js
and ./dist/main.css
.
css minification
To enable css minification you need to install css-minimizer-webpack-plugin (you can use any other minification plugin but I will just show example of using it) via npm install --save-dev css-minimizer-webpack-plugin
or yarn add -D css-minimizer-webpack-plugin
. And include it into your webpack.config.js
file as following:
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
...
module.exports = {
...
optimization: {
minimizer: [new CssMinimizerPlugin()],
},
plugins: [
...,
new CssMinimizerPlugin(),
],
...
}
To make sure your css is minfified you just need to run webpack build and checkout bundled css file in dist directory. If it has no unnecessary spaces or lines wrap after legal comments that means you css is minified ;)