4

I am using grunt to minify some JS files. It would be nice to include the filename in the banner. I have found several examples how to include the package name in the banner, but I haven't yet managed to get the filename in there. So: What do I have to put in the gruntfile (see below) instead of pkg.name to get the source filename (or the dest filename) in there?

Thanks in advance

module.exports = function(grunt) {

   // Project configuration.
   grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),
      uglify: {
         options: {
            banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
         },
         build: {
            files: [{
               expand: true,
               src: '**/*.js',
               dest: 'build',
               cwd: 'src',
               ext: '.min.js'
            }]
         }
      }
   });

   // Load the plugin that provides the "uglify" task.
   grunt.loadNpmTasks('grunt-contrib-uglify');

   // Default task(s).
   grunt.registerTask('default', ['uglify']);
};
fpet
  • 73
  • 8

5 Answers5

1

I tried to do the same thing, and couldn't find any reference to the current filename that was exposed to the template. Here's the workaround I finally figured out; it's a custom task that dynamically creates a new target for each file:

grunt.registerMultiTask('minify', function () {
    this.files.forEach(function (file) {
        var path = file.src[0],
            target = path.match(/src\/(.*)\.js/)[1];

        // store some information about this file in config
        grunt.config('ugtargets.' + target, {
            path: path,
            filename: path.split('/').pop()
        });

        // create and run an uglify target for this file
        grunt.config('uglify.' + target + '.files', [{
            src: [path],
            dest: path.replace(/^src\/(.*)\.js$/, 'build/$1.min.js')
        }]);
        grunt.task.run('uglify:' + target);
    });
});

And my uglify config:

uglify: {
    options: {
        banner: 'Filename: <% ugtargets[grunt.task.current.target].filename %>\n'
    }
}
  • For each file in your source directory, we create a target name out of the filename. The exact process will depend on how your files are named; you'll want to strip out any dots or slashes. Here I used a regex; in my app I actually used fs to read some JSDoc data from the files themselves.
  • Then we store that filename in an object in the Grunt configuration, indexed by the target name. Here I used an object with a couple of properties; you could add more stuff here or just use a plain string if you wanted.
  • Finally we add a target configuration to the uglify config. This is just the src and dest for the current file; we have to do our own filename processing but it's not much work. Then we run the uglify task with the new target.

In the banner template, you can now use grunt.task.current.target to grab the data we stored in the config earlier. Presto!

saltire
  • 343
  • 3
  • 9
0

In case you have more scripts to be uglify is convenient to separate it to particular subtasks with custom property as name identifier.

    uglify: {
        options: {
            banner: 
            '<% var subtask = uglify[grunt.task.current.target]; %>' +
            '/* <%= subtask.name %> <%= pkg.version %> (<%= grunt.template.today("yyyy-mm-dd, HH:MM") %>)\n' +
            ' */\n'
        },
        main: {
            name: 'main.min.js',
            files: [{
                src: 'build/files/js/main.min.js',
                dest: 'build/files/js/main.min.js'
            }]
        },
        vendor: {
            name: 'vendor.min.js',
            files: [{
                src: 'build/files/js/vendor.min.js',
                dest: 'build/files/js/vendor.min.js'
            }]
        }
    }
Martin Surynek
  • 658
  • 6
  • 9
0

Try the following:

banner: grunt.file.read('./folder/file.js'),

https://stackoverflow.com/questions/38854998/dynamic-mapping-and-concat-with-grunt-uglify/

Community
  • 1
  • 1
fidev
  • 1,222
  • 2
  • 21
  • 51
0

https://github.com/mattstyles/grunt-banner/issues/5#issuecomment-33445038

process: function (src, filepath) {} did the job.

For me, I wanna add "//# sourceUrl=xxx.min.js" at the bottom of each uglified .min.js so that I can debug these dynamically loaded .min.js. The following simple Gruntfile.js works for me:

module.exports = function (grunt) {
    var cwd = "/Branding/Layouts/JS/";
    var src = [
                "file1.js",
                "file2.js",
                "file3.js"
    ];

    var minified_src = [];
    for (i=0;  i< src.length; i++)
        minified_src.push(src[i].replace(/\.js$/g, ".min.js"));

    var config = grunt.initConfig({
        "uglify": {
            options: {
                sourceMap: true
            },
            target: {
                files: [
                    {
                        expand: true,
                        cwd: cwd,
                        src: src,
                        dest: cwd,
                        ext: ".min.js",
                        extDot: "last"
                    }
                ]
            }
        },
        concat: {
            options: {
                process: function (src, filepath) {
                    return src + "\n//# sourceURL=" + filepath.split("/").slice(-1);
                }
            },
            target: {
                files: [
                    {
                        expand: true,
                        cwd: cwd,
                        src: minified_src,
                        dest: cwd
                    }
                ]
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.registerTask('default', ['uglify', 'concat']);
};

Note: uglify can't preserve a comment that is not inside a code block (like //# sourceMap=xxx.js), I have to use concat to append the comment after uglify is done.

Wow, this is my first stackoverflow post.

Canada Wan
  • 404
  • 6
  • 7
-1

Documentation is indeed scarse, but <%= pkg.name %> in the banner string implies you can also do <% for ( var s in grunt) { %> \ngrunt.<%=s%><% } %> or even <% for ( var s in this) { %> \nthis.<%=s%><% } %>.

So (after some searching) to get the filename you can do this:

var bannerTemplate = '<%' +' var subtask = uglify[grunt.task.current.target];' +' var file = subtask?subtask.dest:\'\';' +' var filename = file.split(\'/\').pop();' +'%>' +'/*! <%= filename %>' +'\n * version: <%= pkg.version %>' +'\n * author: <%= pkg.author %>' +'\n */\n';

Sjeiti
  • 2,468
  • 1
  • 31
  • 33