SASS with Build Tools: npm Scripts & Webpack
Introduction to SASS Build Tools
Modern web development requires build tools to compile SASS, optimize assets, and automate development workflows. In this comprehensive lesson, we'll explore various build tools and how to integrate SASS into your development pipeline, from simple npm scripts to advanced bundlers like Webpack and Vite.
Setting Up npm Scripts for SASS Compilation
npm scripts provide a simple, dependency-free way to compile SASS files. They're defined in your package.json file and can be executed with npm run.
Installing SASS
First, install SASS as a development dependency:
Package Installation
# Install Dart Sass (recommended)
npm install --save-dev sass
# Or install node-sass (legacy, not recommended)
npm install --save-dev node-sass
Basic npm Scripts Configuration
Add compilation scripts to your package.json:
package.json - Basic Scripts
{
"name": "my-project",
"version": "1.0.0",
"scripts": {
"build:css": "sass src/scss/main.scss dist/css/main.css",
"watch:css": "sass --watch src/scss:dist/css",
"build:css:compressed": "sass src/scss/main.scss dist/css/main.min.css --style=compressed"
},
"devDependencies": {
"sass": "^1.69.0"
}
}
Advanced npm Scripts
Create more sophisticated scripts with source maps, error handling, and parallel execution:
package.json - Advanced Scripts
{
"scripts": {
"sass:dev": "sass src/scss:dist/css --source-map --watch",
"sass:build": "sass src/scss:dist/css --no-source-map --style=compressed",
"sass:lint": "stylelint \"src/scss/**/*.scss\" --fix",
"prebuild": "npm run sass:lint",
"build": "npm run sass:build",
"dev": "npm-run-all --parallel sass:dev serve",
"serve": "lite-server"
},
"devDependencies": {
"sass": "^1.69.0",
"npm-run-all": "^4.1.5",
"lite-server": "^2.6.1",
"stylelint": "^15.10.3",
"stylelint-config-standard-scss": "^11.0.0"
}
}
PostCSS Integration with SASS
PostCSS is a tool for transforming CSS with JavaScript plugins. It works perfectly with SASS to add vendor prefixes, minify output, and apply other transformations.
Installing PostCSS
PostCSS Installation
npm install --save-dev postcss postcss-cli autoprefixer cssnano
PostCSS Configuration
Create a postcss.config.js file:
postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')({
overrideBrowserslist: ['last 2 versions', '> 1%', 'IE 11']
}),
require('cssnano')({
preset: ['default', {
discardComments: {
removeAll: true
},
normalizeWhitespace: false
}]
})
]
};
Combined SASS and PostCSS Pipeline
package.json - SASS + PostCSS
{
"scripts": {
"sass:compile": "sass src/scss:dist/css --no-source-map",
"postcss:process": "postcss dist/css/*.css --dir dist/css --replace",
"build:css": "npm run sass:compile && npm run postcss:process",
"watch:sass": "sass --watch src/scss:dist/css",
"watch:postcss": "postcss dist/css/*.css --dir dist/css --watch",
"dev": "npm-run-all --parallel watch:sass watch:postcss"
}
}
Webpack Configuration with SASS
Webpack is a powerful module bundler that can handle SASS compilation along with JavaScript bundling, image optimization, and more.
Installing Webpack and SASS Loaders
Webpack Dependencies
npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save-dev sass-loader sass css-loader style-loader
npm install --save-dev mini-css-extract-plugin css-minimizer-webpack-plugin
Basic Webpack Configuration
webpack.config.js - Basic Setup
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'styles.css'
})
]
};
Advanced Webpack Configuration
webpack.config.js - Production Setup
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
mode: isProduction ? 'production' : 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.[contenthash].js',
clean: true
},
devtool: isProduction ? 'source-map' : 'eval-source-map',
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2
}
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
postcssOptions: {
plugins: [
['autoprefixer'],
['cssnano', { preset: 'default' }]
]
}
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
sassOptions: {
outputStyle: isProduction ? 'compressed' : 'expanded',
includePaths: [path.resolve(__dirname, 'src/scss')]
}
}
}
]
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource'
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource'
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: isProduction ? 'styles.[contenthash].css' : 'styles.css'
})
],
optimization: {
minimizer: [
`...`,
new CssMinimizerPlugin()
]
},
devServer: {
static: './dist',
hot: true,
port: 3000
}
};
};
Using SASS in Webpack Entry
src/index.js - Import SASS
// Import your main SASS file
import './scss/main.scss';
// Your JavaScript code
console.log('Application initialized');
Vite and SASS Integration
Vite is a modern build tool with native SASS support. It requires minimal configuration and offers incredibly fast hot module replacement (HMR).
Installing Vite
Vite Installation
npm install --save-dev vite sass
Vite Configuration
Vite works with SASS out of the box, but you can customize it:
vite.config.js
import { defineConfig } from 'vite';
import path from 'path';
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "sass:math"; @import "@/styles/variables";`,
includePaths: [path.resolve(__dirname, 'src/scss')]
}
},
devSourcemap: true
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
build: {
sourcemap: true,
cssCodeSplit: true,
rollupOptions: {
output: {
assetFileNames: 'assets/[name].[hash][extname]'
}
}
}
});
Vite npm Scripts
package.json - Vite Scripts
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
Gulp with SASS
Gulp is a task runner that can orchestrate complex build workflows. While less popular than Webpack or Vite, it's still used in many projects.
Installing Gulp and SASS
Gulp Installation
npm install --save-dev gulp gulp-sass sass gulp-postcss autoprefixer cssnano gulp-sourcemaps
Gulpfile Configuration
gulpfile.js
const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const sourcemaps = require('gulp-sourcemaps');
// Paths
const paths = {
scss: {
src: 'src/scss/**/*.scss',
dest: 'dist/css'
}
};
// SASS compilation task
function compileSass() {
return gulp.src(paths.scss.src)
.pipe(sourcemaps.init())
.pipe(sass({ outputStyle: 'expanded' }).on('error', sass.logError))
.pipe(postcss([autoprefixer(), cssnano()]))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(paths.scss.dest));
}
// Watch task
function watchFiles() {
gulp.watch(paths.scss.src, compileSass);
}
// Export tasks
exports.sass = compileSass;
exports.watch = watchFiles;
exports.default = gulp.series(compileSass, watchFiles);
Source Maps: Development vs Production
Source maps help you debug compiled CSS by mapping it back to the original SASS files. However, they should be handled differently in development and production.
Development Source Maps
// Full source maps for debugging
sass src/scss:dist/css --source-map --embed-sources
// Webpack development
devtool: 'eval-source-map'
// Vite development
css: {
devSourcemap: true
}
Production Source Maps
// External source maps (don't embed sources)
sass src/scss:dist/css --source-map
// Or disable completely for smaller file size
sass src/scss:dist/css --no-source-map
// Webpack production
devtool: 'source-map' // or false to disable
// Vite production
build: {
sourcemap: true // or false
}
Minification and Optimization
Proper minification can reduce CSS file sizes by 40-60%, significantly improving load times.
SASS Built-in Compression
SASS Output Styles
# Expanded (readable, for development)
sass src/scss:dist/css --style=expanded
# Compressed (minified, for production)
sass src/scss:dist/css --style=compressed
Advanced Optimization with cssnano
cssnano Configuration
// postcss.config.js
module.exports = {
plugins: [
require('cssnano')({
preset: ['advanced', {
discardComments: { removeAll: true },
reduceIdents: false, // Preserve @keyframes names
zindex: false, // Don't modify z-index values
mergeRules: true,
cssDeclarationSorter: true
}]
})
]
};
Hot Module Replacement (HMR)
HMR updates your styles in the browser without a full page reload, preserving application state during development.
Webpack Dev Server with HMR
webpack.config.js - HMR Setup
module.exports = {
devServer: {
static: './dist',
hot: true, // Enable HMR
liveReload: true,
watchFiles: ['src/**/*.scss'],
port: 3000,
open: true
}
};
Vite HMR
Vite has HMR enabled by default with incredibly fast updates:
Vite HMR (Automatic)
// Just run the dev server
npm run dev
// Vite automatically detects SASS changes and updates instantly
Complete Build Setup Example
Here's a complete package.json with all scripts for a professional project:
package.json - Complete Setup
{
"name": "sass-project",
"version": "1.0.0",
"scripts": {
"clean": "rimraf dist",
"sass:dev": "sass src/scss:dist/css --source-map --watch",
"sass:build": "sass src/scss:dist/css --no-source-map --style=compressed",
"postcss:dev": "postcss dist/css/*.css --dir dist/css --watch",
"postcss:build": "postcss dist/css/*.css --dir dist/css --replace",
"lint:scss": "stylelint \"src/scss/**/*.scss\" --fix",
"dev": "npm-run-all clean --parallel sass:dev serve",
"build": "npm-run-all clean lint:scss sass:build postcss:build",
"serve": "browser-sync start --server dist --files \"dist/**/*\"",
"webpack:dev": "webpack serve --mode=development",
"webpack:build": "webpack --mode=production",
"vite:dev": "vite",
"vite:build": "vite build",
"vite:preview": "vite preview"
},
"devDependencies": {
"sass": "^1.69.0",
"postcss": "^8.4.31",
"postcss-cli": "^10.1.0",
"autoprefixer": "^10.4.16",
"cssnano": "^6.0.1",
"stylelint": "^15.10.3",
"stylelint-config-standard-scss": "^11.0.0",
"npm-run-all": "^4.1.5",
"rimraf": "^5.0.5",
"browser-sync": "^2.29.3",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"sass-loader": "^13.3.2",
"css-loader": "^6.8.1",
"mini-css-extract-plugin": "^2.7.6",
"css-minimizer-webpack-plugin": "^5.0.1",
"vite": "^5.0.0"
}
}
Exercise 1: Set Up Basic npm Scripts
Create a new project with npm scripts for SASS compilation:
- Initialize a new npm project:
npm init -y - Install SASS:
npm install --save-dev sass - Create a
src/scss/main.scssfile with some styles - Add scripts to
package.jsonfor building and watching SASS - Test the scripts:
npm run build:cssandnpm run watch:css
Exercise 2: Integrate PostCSS
Add PostCSS to your SASS pipeline:
- Install PostCSS, autoprefixer, and cssnano
- Create a
postcss.config.jsfile - Update your npm scripts to run PostCSS after SASS compilation
- Add a CSS property that needs prefixing (like
user-select: none;) and verify autoprefixer adds vendor prefixes - Compare file sizes before and after cssnano optimization
Exercise 3: Configure Webpack or Vite
Set up a complete build system with either Webpack or Vite:
- Choose either Webpack or Vite and install required dependencies
- Create the configuration file (
webpack.config.jsorvite.config.js) - Configure SASS loading with source maps
- Set up development and production modes
- Test hot module replacement by running the dev server and editing SASS files
- Build for production and verify output is minified and optimized