2

How to compile SASS and minify CSS and create its map with gulp 4 in same task

Im using Gulp 4, i wonder if there is a way to put the css with its map and also put the css minified with its map, But in the same task, i mean something like this:

- css
    - main.css
    - main.css.map
    - main.min.css
    - main.min.css.map

My current code actually does it but i have two task

const gulp = require('gulp');
const autoprefixer = require('gulp-autoprefixer');
const cleanCSS = require('gulp-clean-css');
const sass = require('gulp-sass');
const sourcemaps = require('gulp-sourcemaps');
const rename = require('gulp-rename');

//declare the scr folder
let root = '../src' + '/';
let scssFolder = root + 'scss/';

//declare the build folder
let build = '../build/' + '/';
let cssFolder = build + 'css';

// Compile scss into css
function css() {
  return gulp
    .src(scssFolder + 'main.scss')
    .pipe(sourcemaps.init({ loadMaps: true }))
    .pipe(
      sass({
        outputStyle: 'expanded',
      }).on('error', sass.logError)
    )
    .pipe(autoprefixer('last 2 versions'))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest(cssFolder));
}

//minify css
function minCSS() {
  return gulp
    .src(scssFolder + 'main.scss')
    .pipe(sourcemaps.init({ loadMaps: true }))
    .pipe(
      sass({
        outputStyle: 'compressed',
      }).on('error', sass.logError)
    )
    .pipe(autoprefixer('last 2 versions'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest(cssFolder));
}

exports.css = css;
exports.minCSS = minCSS;

and id like to know either if i can put in one task or how can i call them in one task for example:

function css() {
  return gulp
    .src(scssFolder + 'main.scss')
    .pipe(sourcemaps.init({ loadMaps: true }))
    .pipe(
      sass({
        outputStyle: 'expanded',
      }).on('error', sass.logError)
    )
    .pipe(autoprefixer('last 2 versions'))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest(cssFolder))

//Put here the minify code
.pipe(cleanCSS())
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(cssFolder));

}

but the previous code doesn´t work because it creates main.css and main.css.map

2 Answers2

0

Create new function where you run both functions in series from your first code.

Example

function compileAndMinify(){
   return gulp.series(css(),minCss()); 
}
AvgustinTomsic
  • 1,809
  • 16
  • 22
0

Ok, so I have what I think might be the ultimate solution for this problem if you are using gulp 4. Also I am using babel to write my gulp file in es6 via "gulpfile.babel.js" so pardon if this example looks weird (I split my gulp 4 builds up into multiple js modules).

This is a non question specific answer, but it illustrates how I output min and non min css and source maps in the same task, by having my gulp task run it twice via gulp 4 parallel.

'use strict';
import config from './config';
import yargs from 'yargs';
import { src, dest, parallel, series } from 'gulp';
import concat from 'gulp-concat';
import rename from 'gulp-rename';
import csso from 'gulp-csso';
import sass from 'gulp-sass';
import tildeImporter from 'node-sass-tilde-importer';
import sassVar from 'gulp-sass-variables';
import sourcemaps from 'gulp-sourcemaps';

sass.compiler = require('node-sass');
var args = yargs.argv;

class isolatedVendorBuild {
    static build(done, destination, fileName) {
        //this is the actual gulp-sass build function, that will be wrapped by two other gulp4 tasks
        let internalBuild = ((shouldMin) => {
            //store the stream to a variable before returning it, so we can conditionally add things to it
            let ret = src(config.paths.srcSharedIsolatedVendorScss)
                .pipe(sourcemaps.init())
                .pipe(concat(fileName))
                .pipe(sassVar({
                    $env: args.prod ? 'prod' : 'dev'
                }))
                .pipe(sass({
                    importer: tildeImporter,
                    outputStyle: 'nested'
                }).on('error', sass.logError));

            if (shouldMin) {
                //if the function was called with shouldMin true, then reset the stream from the previous stream but with the rename .min and csso call added to it
                ret = ret.pipe(rename({ suffix: '.min' }));
                ret.pipe(csso({ sourceMap: true }));
            }
            //reset the stream to the previous ret and add sourcemaps.write and destination output to it
            ret = ret.pipe(sourcemaps.write('.'))
                .pipe(dest(destination));

            //return the complete stream
            return ret;

        });


        //create two wrapper functions for the internal build to be called in gulp since gulp can't pass arguments to functions treated as gulp tasks
        function buildStylesUnMinified() {
            return internalBuild(false); //pass false for shouldMin and it will output the unminified css and source map
        }

        function buildStylesMinified() {
            return internalBuild(true); //pass true for shouldMin and it will output the minified css and source map with the .min suffix added to the file name.
        }

        //the magic, we use gulp parallel to run the unminified version and minified version of this sass build at the same time calculating two separate streams of css output at the same time. 
        return parallel(buildStylesUnMinified, buildStylesMinified)(done);
    }
}

export default isolatedVendorBuild;

I've seen other solutions that involve outputting the non minified css first, then using that as an input for the minification task. That works, but it forces synchronous dependencies and that get's build times crawling to a snails pace in complex builds.

I came up with this method just recently solving for this in a new project with multiple scss output files. I like it because both minified and unminified tasks run at the same time and I was able to get my main build to let the entire scss output process be async, as in, not depend on it completing before doing the scripts and stuff.

Ryan Mann
  • 5,178
  • 32
  • 42