0

I am trying to move away from gulp and use npm scripts. We have developers that use different versions of node/gulp and the dependence on plugins and deprecation's has been an unwanted hassle.

I am trying to convert our gulp script to npm but there are a few areas I'm stuck on. I'm having issues converting from gulp-sourcemaps to npm map-stream and converting from gulp-uglify to uglifyjs.

Here is the gulp file we are currently using:

/*
This file in the main entry point for defining Gulp tasks and using Gulp plugins.
Click here to learn more. http://go.microsoft.com/fwlink/?LinkId=518007
*/

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');
var pump = require('pump');
var del = require('del');

// set a variable telling us if we're building in release
var isRelease = true;
if (process.env.NODE_ENV && process.env.NODE_ENV !== 'Release') {
    isRelease = false;
}

var config = {
    //Include all js files but exclude any min.js files
    src: ['Scripts/*.js', '!Scripts/*.min.js']
}

//delete the output file(s)
gulp.task('clean', function () {
    //del is an async function and not a gulp plugin (just standard nodejs)
    //It returns a promise, so make sure you return that from this task function
    //  so gulp knows when the delete is complete
    return del(['Scripts/*.min.js', 'Scripts/Maps/*.map']);
});

 // Combine and minify all files from the app folder
// This tasks depends on the clean task which means gulp will ensure that the 
// Clean task is completed before running the scripts task.
gulp.task('scripts', ['clean'], function (cb) {

    pump([
      gulp.src(config.src),
      sourcemaps.init(),
      uglify({ mangle: isRelease }),
      rename({ suffix: '.min' }),
      sourcemaps.write('Maps', { includeContent: false, sourceRoot: './' }),
      gulp.dest('Scripts/')
    ],
    cb
    );
});

//Set a default tasks
gulp.task('default', ['scripts'], function () { });

Here is my current npm script (still has some errors):

 /*
This is the main entry point for defiinng npm tasks
*/

const del = require('del');
var map = require('map-stream');
var pump = require('pump');
var vfs = require('vinyl-fs');
var uglifyjs = require('uglify-js');

// set a variable telling us if we're building in release
var isRelease = true;
if (process.env.NODE_ENV && process.env.NODE_ENV !== 'Release') {
    isRelease = false;
}
console.log(process.env.NODE_ENV);

//task to delete output files
(async () => {
    const deletedPaths = await del(['Scripts/*.min.js', 'Scripts/Maps/*.map']);

    console.log('Deleted files and folders:\n', deletedPaths.join('\n'));
})();




var log = function(file, cb) {
    console.log(file.path);
    cb(null, file);
  };

//    vinyl metadata object
//   Include all js files but exclude any min.js files

  pump([
    vfs.src(['Scripts/*.js', '!Scripts/*.min.js']),
    map(log),
    uglifyjs({mangle:isRelease}),
    rename({ suffix: '.min' }),

    (vfs.dest('Scripts/'))

 ])

The mapping should create a Maps folder under the Scripts directory.

 Scripts
     --Maps
           --jquery.min.js.map
           --jquery-1.4.1.min.js.map

Any help would be appreciated.

Thanks!

Stacker
  • 137
  • 3
  • 12

1 Answers1

0
/*
 *   This is the main entry point for defining npm tasks
 *   Author: *****
 *   Date: 06/03/2019
*/

const del = require('del');
var Uglify = require("uglify-js"),
    fs = require('fs'),
    async = require('async'),
    path = require('path'),
   rename = require('rename'),
   parentDir = 'Scripts';

Checking the build type (Release, Production, Debug etc.) is done using node so there weren't any changes to be made in this part of the script.

// set a variable telling us if we're building in release
var isRelease = true;
if (process.env.NODE_ENV && process.env.NODE_ENV !== 'release') {
   isRelease = false;
}
 console.log(process.env.NODE_ENV);

As for the npm del module, I opted for the synchronous method. The reason is that I wanted each file to be processed separately instead of in parallel. The async method kept missing the .acingore file and there aren't many files that need to be deleted anyway.

//  Returns an array of deleted paths
const deletedPaths = del.sync(['Scripts/*.min.js', 'Scripts/Maps/*.map', 'Scripts/.acignore']);

console.log('Deleted files and folders:\n', deletedPaths.join('\n'));

This block does all the work. This function runs an array of functions in series, each passing their results to the next in the array. Each function is passed a callback on completion.

async.waterfall([
function (cb) {
    fs.readdir(parentDir, cb);
},
function (files, cb) {
    // files is just an array of file names, not full path
    console.log('Files being looped through:\n');
    // run 10 files in parallel
    async.eachLimit(files, 10, function (filename, done) {
        var filePath = path.join(parentDir, filename);

        var sourceFile = filename;

        if (!fs.lstatSync(filePath).isDirectory()) {

            // create a .temp file to be minified
            fs.copyFileSync(filePath, filePath + '.temp', (err) => {
                if (err) throw err;
                // console.log(filePath + ' was copied to ' + filePath + '.temp');
            });
            //  path the .temp file
            var tempfilePath = path.join(parentDir, filename + '.temp');
            //  console.log('tempfilePath: ' + tempfilePath);

            //  check for /Maps directory, if not, create it
            var mapsDir = parentDir + '/Maps';
            try {
                if (!fs.existsSync(mapsDir)) {
                    fs.mkdirSync(mapsDir)
                }
            } catch (err) {
                console.error(err)
            }

            //  rename file to add .min suffix for minified files
            filename = rename(filename, { suffix: '.min' });
            //  console.log('filename after rename\n' + filename + '\n');
            var newfilePath = path.join(parentDir, filename);
            //   console.log('filePath after rename\n' + newfilePath + '\n');

            //  Synchronous rename
            fs.renameSync(tempfilePath, newfilePath);

            //  get contents of sourceFile 
            //  The source file must be interpolated with [] in order
            //  to be mapped correctly, otherwise your map will get the content
            //  of the source file but not have a link back to the source
            try {
                var code = {
                    [sourceFile]: fs.readFileSync(filePath, 'utf-8')
                };
                console.log(code);
            } catch (e) {
                console.log('Error:', e.stack);
            }

            //  minify file 
            // the syntax for uglifyjs minify is minify(code, options)
            // therefore you need the contents of the file in order to minify it
            // and source map it
            var uglyCode = Uglify.minify(code,
                {
                    mangle: isRelease,
                    sourceMap: {
                        includeSources: false,
                        filename: '../' + filename,
                        root: '../',
                        url: 'Maps/' + filename,
                    },
                }

            );

            //  console.log('Source file: ' + sourceFile);

            //  write minified file to directory
            fs.writeFile(newfilePath, uglyCode.code, function (err) {
                if (err) {
                    console.log(err);
                } else {
                    console.log(filename + " has been mangled");
                }
            }
            );

            //  write map file to directory
            fs.writeFile(mapsDir + '/' + filename + '.map', uglyCode.map, function (err) {
                if (err) {
                    console.log(err);
                } else {
                    console.log(filename + '.map' + " has been mapped");
                }
            }
            );
            done();
        }
    }, cb);
}
], function (err) {
err && console.trace(err);

console.log('\nNo more files in path\n');
});

SIDE NOTE: If you're running node 10+ and you cannot set the path to npm in your .csproj file, install node globally and you don't need to set the path.

Hopefully my comments in the code are sufficient. Good luck if you are trying to move away from gulp and transition to npm!

Stacker
  • 137
  • 3
  • 12