Sometimes you just want to use Webpack for style-only entries. While this tutorial is mostly for my sanity (I have to look this up all the time), I thought I’d share it in case others have the same issue.
Webpack is generally used for JavaScript only, however you can configure it to accept only SCSS files.
Project Structure
Here’s a very simple project structure. The Ascii folder structure is courtesy of the Ascii Tree Generator.
src/
├─ scss/
│ ├─ admin.scss
│ ├─ frontend.scss
package.json
webpack.config.js
Code language: AsciiDoc (asciidoc)
Webpack Config
As of this writing, this technique only works with Webpack ~4.0. I’ll share my package.json in a bit. Let’s dive into the Webpack config.
const path = require('path');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = [
{
mode: process.env.NODE_ENV,
entry: {
'sce-admin': ['./src/scss/admin.scss'],
'sce-frontend': ['./src/scss/frontend.scss'],
},
output: {},
module: {
rules: [
{
test: /\.scss$/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourceMap: true,
url: false,
},
},
'sass-loader',
],
},
],
},
devtool: 'source-map',
plugins: [new FixStyleOnlyEntriesPlugin(), new MiniCssExtractPlugin()],
},
];
Code language: JavaScript (javascript)
Let’s dive into some dependencies.
const path = require('path');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
Code language: JavaScript (javascript)
The obvious dependencies are webpack-fix-style-only-entries and mini-css-extract-plugin. We’ll need both.
- The
mini-css-extract-plugin
will create a new file per scss file. - The
webpack-fix-style-only-entries
will remove the JS file for each stylesheet.
By default, Webpack will create a JS file for each stylesheet endpoint. We use the webpack-fix-style-only-entries
to get around this.
Let’s dive into the next webpack section.
module.exports = [
{
mode: process.env.NODE_ENV,
entry: {
'sce-admin': ['./src/scss/admin.scss'],
'sce-frontend': ['./src/scss/frontend.scss'],
},
output: {},
Code language: JavaScript (javascript)
We set our environment variables, set the entry points (highlighted), and choose not to output anything.
So far so good.
module: {
rules: [
{
test: /\.scss$/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourceMap: true,
url: false,
},
},
'sass-loader',
],
},
],
},
Code language: JavaScript (javascript)
I have highlighted the important parts.
- We test for SCSS files.
- We exclude node_modules.
- We use the MiniCssExtractPlugin to create the separate files and also to minify the output for production use.
- sass-loader and css-loader are needed to process the SCSS files.
I apologize for not being more descriptive above. Some of these dependencies were a result of trial-and-error.
Finally, we initialize a source map and define our plugins.
devtool: 'source-map',
plugins: [new FixStyleOnlyEntriesPlugin(), new MiniCssExtractPlugin()],
Code language: JavaScript (javascript)
For convenience, here is the entire Webpack file again:
const path = require('path');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = [
{
mode: process.env.NODE_ENV,
entry: {
'sce-admin': ['./src/scss/admin.scss'],
'sce-frontend': ['./src/scss/frontend.scss'],
},
output: {},
module: {
rules: [
{
test: /\.scss$/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourceMap: true,
url: false,
},
},
'sass-loader',
],
},
],
},
devtool: 'source-map',
plugins: [new FixStyleOnlyEntriesPlugin(), new MiniCssExtractPlugin()],
},
];
Code language: JavaScript (javascript)
I’m sure you groovy JavaScript/Webpack devs can make this snippet better. I say, have at it.
Package.json
Here’s a sample package.json file I use for a plugin called Simple Comment Editing (GitHub).
{
"name": "simple-comment-editing",
"version": "3.0.0",
"description": "Simple Comment Editing for your users",
"main": "gruntfile.js",
"scripts": {
"start": "webpack --watch --mode development",
"dev": "webpack --mode development",
"build": "webpack --mode production",
"lint": "eslint ."
},
"repository": {
"type": "git",
"url": "git+https://github.com/MediaRon/simple-comment-editing.git"
},
"keywords": [
"comment",
"editing",
"simple",
"comment",
"editing"
],
"author": "Ronald Huereca",
"license": "GPL-3.0-or-later",
"bugs": {
"url": "https://github.com/MediaRon/simple-comment-editing/issues"
},
"homepage": "https://github.com/MediaRon/simple-comment-editing#readme",
"devDependencies": {
"css-loader": "^5.2.6",
"grunt": "^1.4.0",
"grunt-cli": "^1.4.2",
"grunt-contrib-compress": "^2.0.0",
"mini-css-extract-plugin": "^1.6.0",
"sass-loader": "^10.0.5",
"style-loader": "^2.0.0",
"webpack": "^4.42.0",
"webpack-cli": "^4.5.0",
"webpack-fix-style-only-entries": "^0.6.1"
},
"dependencies": {
"sass": "^1.34.0"
}
}
Code language: JavaScript (javascript)
Download a Sample ZIP
(Sample SCSS files included. Pardon my horrible SCSS skills).
If you choose to use the above package.json
, you’re welcome to rename the objects to make it your own.
After that, just run npm install
inside the project directory and you should be set.
- Start watching your SCSS files by running:
npm run start
- Run the dev SCSS by running:
npm run dev
- And finally, when you’re done, run:
npm run build
For example, when I run npm run start
, I receive the following output:
That’s it!
If all is well, you’ll end up with this folder structure.
dist/
├─ sce-admin.css
├─ sce-admin.css.map
├─ sce-frontend.css
├─ sce-frontend.css.map
src/
├─ scss/
│ ├─ admin.scss
│ ├─ frontend.scss
package.json
webpack.config.js
Code language: AsciiDoc (asciidoc)
Questions?
Please leave a comment below and I’ll do my best to respond and/or update the article with more information.
Thank you for reading.