My Webpack no longer converts css from main.css
into index.css
upon running the build script. I need help figuring this out.
I have a plain HTML/Sass website, and I'm attempting to push some CSS updates into production. When I updated to Webpack 5 in April 2023, everything worked fine (with some tweaks)¹. I could modify the code and see it reflected served at localhost.
As I understand it, Webpack converts the .scss
code into .css
code, and puts it into a main.css
file within a .gitignore
'd /dist
directory. The web server then reads from the main.css
file. This works fine and dandy in dev, but deploying into production no longer converts that code into an index.css
file.
This worked in April, but now it does not do so, and I cannot figure out why. I've only made changes within my index.html
and index.scss
files, so the edit/test/deploy process should have remained unchanged.
I've tried searching forums for assistance, but most of those similar issues deal with versions of Webpack much older than v5, and those solutions have become deprecated.
Here's my Webpack:
// Generated using webpack-cli https://github.com/webpack/webpack-cli
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const isProduction = process.env.NODE_ENV == 'production';
const stylesHandler = MiniCssExtractPlugin.loader;
const config = {
entry: './src/index.js',
// disabling cache in watch mode
cache: false,
output: {
path: path.resolve(__dirname, 'dist'),
assetModuleFilename: 'public/[name][ext]',
},
devServer: {
open: true,
host: 'localhost',
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
}),
new MiniCssExtractPlugin(),
],
module: {
rules: [
{
test: /\.html$/i,
loader: "html-loader",
},
{
test: /\.(js|jsx)$/i,
loader: 'babel-loader',
},
{
test: /\.css$/i,
use: [stylesHandler,'css-loader'],
sideEffects: true,
},
{
test: /\.s[ac]ss$/i,
use: [stylesHandler, 'css-loader', 'sass-loader'],
sideEffects: true,
},
{
test: /\.(png|svg|jpg|jpeg|gif|pdf|eot|ttf|woff|woff2)$/i,
type: 'asset/resource',
},
],
},
};
module.exports = () => {
if (isProduction) {
config.mode = 'production';
} else {
config.mode = 'development';
}
return config;
};
¹ MiniCssExtractPlugin
is required for sass to work properly & cache: false,
for main.css
to get live updates in watch mode
Here's my package.json:
{
"version": "1.0.0",
"description": "JF Portfolio",
"name": "jf-portfolio",
"scripts": {
"build": "webpack --mode=production --node-env=production",
"build:dev": "webpack --mode=development",
"build:prod": "webpack --mode=production --node-env=production",
"watch": "webpack --watch",
"serve": "webpack serve & compile:sass",
"compile:sass": "node-sass -w styles/index.scss src/index.css --recursive"
},
"devDependencies": {
"@babel/core": "^7.21.4",
"@babel/preset-env": "^7.21.4",
"babel-loader": "^9.1.2",
"css-loader": "^6.7.3",
"html-loader": "^4.2.0",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.7.5",
"node-sass": "^8.0.0",
"prettier": "^2.8.7",
"sass": "^1.60.0",
"sass-loader": "^13.2.2",
"style-loader": "^3.3.2",
"webpack": "^5.77.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.13.1"
}
}
My basic directory structure:
/dist
(uncommited directory containing Webpack emitted files)
/public
(all content stored top-level, no sub-directories)index.html
main.css
(webpack converts index.scss
into css in this file)main.js
/public
(contains content in sub-directories)
/fonts
/images
/svg-icons
adocument.pdf
anotherdocument.pdf
/src
(contains the final "converted" CSS file for import into HTML)
index.css
(this is the file that is no longer getting updated from main.css
)index.js
/styles
index.scss
(this is where I make stylistic changes)index.html
When I initially set up this version of Webpack, updates from index.scss
where pushed into main.css
live (I think it's called hot-loading?). And when it came time to deploy, code from main.css
was pushed into index.css
. Basically:
index.scss --> main.css --> index.css
dev --> serve --> deploy
Essentially, index.css
is supposed to be the "Okay I'm ready to go live with this" file, and it is the one which is imported in the index.html
. However, updates are no longer making it from main.css
into index.css
.
dev ✅ --> serve ✅ --> deploy ❌
Things I have attempted:
npm run build:prod
& npm run build:dev
index.css
to see if that will force a refill.index.css
altogether to see if a replacement will get generated./node_modules
.At the moment, my only recourse is to manually copy the code from main.css
into index.css
and then fix all the imports/references so they use the correct paths (remember, webpack emits it all into /dist/public
with no further sub-directories).
I need help! Please and thank you in advance!
I do believe I found a solution, and it's quite silly. There was an error somewhere along the way with the script which wasn't logged out anywhere obviously in the terminal where the compile:sass
script either wasn't running, or there was something else that conflicted with its operation. Live updates on the screen weren't working, and changes saved to index.scss
were not being transpiled into index.css
.
I found a StackOverflow comment here about running npm scripts concurrently using an appropriately named npm package: concurrently
.
With concurrently
installed, I modified my package.json
to be this for my serve command:
// old
"serve": "webpack serve & compile:sass",
// new
"serve": "concurrently --kill-others \"webpack serve\" \"npm run compile:sass\"",
My index.css
now receives streaming updates from any changes I make in my index.scss
whenever the file is saved.