usemin define custom step options - gruntjs

I have a Gruntfile running concat and uglify with specific options (i.e. mangle toplevel variables) and then I use sed to update the references to the minified files in index.html. This solution works but is not very maintainable because of sed. I was trying to use usemin instead but I could not figure out how to define my own custom steps with the right options for uglifyjs and the doco lacks in examples to do that. I tried to use the same uglify task I had written before:
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
mangle: {
except: ['$', 'd3'],
toplevel: true
}
},
build: {
src: 'demo/js/<%= pkg.name %>.js',
dest: 'demo/js/<%= pkg.name %>.min.js'
}
},
useminPrepare : {
html : 'src/index.html',
options: {
flow: {
steps: {'js' : ['uglify'] }
}
}
}
but I am getting this error:
Warning: Cannot find module 'path-to-module\node_modules\grunt-usemin\lib\config\uglify' Use --force to continue.
Is it possible to do this and if so, what am i doing wrong here?

Try replacing uglify with uglifyjs in your flow options.

Related

How to include third party library with Grunt

New to Grunt, and have been using it for the first time to combine/minify JS files for a project.
Currently have this (relevant section) in Gruntfile.js:
concat:
{
options:
{
banner: '<%= banner %>',
stripBanners: true
},
dist:
{
src:
[
'build/js/sample_file',
'build/js/another_file.js'
],
dest: 'dist/<%= pkg.build_name %>-<%= pkg.version %>.js'
}
},
uglify:
{
options:
{
banner: '<%= banner %>'
},
dist:
{
src: '<%= concat.dist.dest %>',
dest: 'dist/<%= pkg.build_name %>-<%= pkg.version %>.min.js'
}
},
That's working fine, but I'm not sure how to do the next thing I need. My project requires Hammer.js.
I could just include the library in the concat, but this doesn't seem right to me for 2 reasons. It's already minified (I could get un-minified, but seems a bit of a waste of time when minified already), and it would seem Grunt would be a bit cleverer than this, and could be used to download the latest Hammer library for me?
How do I get Grunt to include a third-party JS library in the uglified code it builds?
use bower for your dependency-management of vendor libraries
use grunt for linting, testing, building
it's not possible to tell you on how to combine these two, as your question is to unspecific.
in general i would use yeoman and some generator to get my project setup. if none of them satisfies your needs, try to learn from them!

Grunt command always run the same Gruntfile

i'm trying to learn Grunt and i create a file, cd to there, and use the grunt command, but doesn't execute my file, but executes other that belongs to a personal project made with yeoman, and no matter the place in the terminal, always run that project. I use:
$ grunt --base "/Users/user/Documents/Ejercicios angular/Ui-routes-tutorial/"
and it shows me:
Warning: Task "newer:jshint" not found. Use --force to continue.
Aborted due to warnings.
Execution Time (2014-04-18 13:41:21 UTC)
loading tasks 3ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 60%
default 2ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 40%
Total 5ms
Here is my file:
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: {
src: 'src/<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
}
}
});
// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-uglify');
// Default task(s).
grunt.registerTask('default', ['uglify']);
};
The error shows Task "newer:jshint" not found, but in my file i don't use that! Can you help me please?
Have you tried CD to the directory of the project, then do a npm install to ensure all the modules defined in the package file are installed, and then run your grunt command?

Grunt uglify not finding files

I have the following directory structure:
--development
-js
-pages
--js
-pages
I'm trying to take all files in development/js/pages and output them js/pages and minify them using grunt uglify but still keep seperate files - I don't want to combine all the files together. I've tried the following:
build: {
src: 'development/js/pages/*.js',
dest: 'js/page',
options: {
sourceMap: true,
compress: true,
mangle: true
}
}
but this gives me an error: unable to write js/page file
Then I tried this, which is on the uglify documentation:
build : {
files: [{
cwd: 'development/js/pages',
src: '*.js',
dest: 'js/page'
}],
options : {
sourceMap: true,
compress: true,
mangle: true
}
}
but this just gives me this error for each file in development/js/pages:
source File "filename.js" not found
and then another error saying Destination (js/page) not written because the source files are empty.
Any ideas why?
For anyone else looking the second option above almost worked but I needed to remove the options block and include expand in the files block:
pages: {
files: [{
expand: true,
cwd: 'development/js/page',
src: '*.js',
dest: 'js/page/',
ext : '.min.js',
}]
}
I wanted to answer with another option.
Here is how I write my Uglify Grunt task incase you want to keep your options. It's setup to read as (dest : src), I also concat all my library files in task prior to Uglify.
-
uglify: {
options: {
// the banner is inserted at the top of the output
banner: '/* \n Site: <%= pkg.name %> \n Version: <%= pkg.version %> \n Build Date: <%= grunt.template.today("mm-dd-yyyy") %> \n */\n \n'
},
site: {
files: {
'./_build/js/lib/lib.min.js': ['<%= concat.site.dest %>'],
'./_build/js/app/app.min.js': ['./_build/js/app/app.js']
}
}
},

Why is it recommended to use concat then uglify when the latter can do both?

I keep seeing the recommendation for making JS files ready for production to be concat then uglify.
For example here, in on of Yeoman's grunt tasks.
By default the flow is: concat -> uglifyjs.
Considering UglifyJS can do both concatenation and minification, why would you ever need both at the same time?
Thanks.
Running a basic test to see if there is a performance difference between executing concat and then uglify vs. just uglify.
package.json
{
"name": "grunt-concat-vs-uglify",
"version": "0.0.1",
"description": "A basic test to see if we can ditch concat and use only uglify for JS files.",
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-concat": "^0.5.0",
"grunt-contrib-uglify": "^0.6.0",
"load-grunt-tasks": "^1.0.0",
"time-grunt": "^1.0.0"
}
}
Gruntfile.js
module.exports = function (grunt) {
// Display the elapsed execution time of grunt tasks
require('time-grunt')(grunt);
// Load all grunt-* packages from package.json
require('load-grunt-tasks')(grunt);
grunt.initConfig({
paths: {
src: {
js: 'src/**/*.js'
},
dest: {
js: 'dist/main.js',
jsMin: 'dist/main.min.js'
}
},
concat: {
js: {
options: {
separator: ';'
},
src: '<%= paths.src.js %>',
dest: '<%= paths.dest.js %>'
}
},
uglify: {
options: {
compress: true,
mangle: true,
sourceMap: true
},
target: {
src: '<%= paths.src.js %>',
dest: '<%= paths.dest.jsMin %>'
}
}
});
grunt.registerTask('default', 'concat vs. uglify', function (concat) {
// grunt default:true
if (concat) {
// Update the uglify dest to be the result of concat
var dest = grunt.config('concat.js.dest');
grunt.config('uglify.target.src', dest);
grunt.task.run('concat');
}
// grunt default
grunt.task.run('uglify');
});
};
In src, I've put a bunch of JS files, including the uncompressed source of jQuery, copied several times, spread around into subfolders. Much more than what a normal site/app usually has.
Turns out the time it takes to concat and compress all of these files is essentially the same in both scenarios.
Except when using the sourceMap: true option on concat as well (see below).
On my computer:
grunt default : 6.2s (just uglify)
grunt default:true : 6s (concat and uglify)
It's worth noting that the resulting main.min.js is the same in both cases.
Also, uglify automatically takes care of using the proper separator when combining the files.
The only case where it does matter is when adding sourceMap: true to the concat options.
This creates a main.js.map file next to main.js, and results in:
grunt default : 6.2s (just uglify)
grunt default:true : 13s (concat and uglify)
But if the production site loads only the min version, this option is useless.
I did found a major disadvantage with using concat before uglify.
When an error occurs in one of the JS files, the sourcemap will link to the concatenated main.js file and not the original file. Whereas when uglify does the whole work, it will link to the original file.
Update:
We can add 2 more options to uglify that will link the uglify sourcemap to concat sourcemap, thus handling the "disadvantage" I mentioned above.
uglify: {
options: {
compress: true,
mangle: true,
sourceMap: true,
sourceMapIncludeSources: true,
sourceMapIn: '<%= paths.dest.js %>.map',
},
target: {
src: '<%= paths.src.js %>',
dest: '<%= paths.dest.jsMin %>'
}
}
But it seems highly unnecessary.
Conclusion
I think it's safe to conclude that we can ditch concat for JS files if we're using uglify, and use it for other purposes, when needed.
In the example you mention, which I'm quoting below, the files are first concatenated with concat and then uglified/minified by uglify:
{
concat: {
'.tmp/concat/js/app.js': [
'app/js/app.js',
'app/js/controllers/thing-controller.js',
'app/js/models/thing-model.js',
'app/js/views/thing-view.js'
]
},
uglifyjs: {
'dist/js/app.js': ['.tmp/concat/js/app.js']
}
}
The same could be achieved with:
{
uglifyjs: {
'dist/js/app.js': [
'app/js/app.js',
'app/js/controllers/thing-controller.js',
'app/js/models/thing-model.js',
'app/js/views/thing-view.js'
]
}
}
Typically, the task clean would then run after tasks that write to a temporary folder (in this example concat) and delete whatever content is in that folder. Some people also like to run clean before tasks like compass, to delete things like randomly named image sprites (which are newly generated every time the task runs). This would keep wheels turning even for the most paranoid.
This is all a matter of preference and workflow, as is with when to run jshint. Some people like to run it before the compilation, others prefer to run it on compiled files.
Complex projects with an incredible amount of JavaScript files - or with a increasingly broad number of peers & contributors, might choose to concatenate files outside uglify just to keep things more readable and maintainable. I think this was the reasoning behind Yeoman's choice of transformation flow.
uglify can be notoriously slow depending of the project's configuration, so there might be some small gain in concatenating it with concat first - but that would have to be confirmed.
concat also supports separators, which uglify doesn't as far as README.md files are concerned.
concat: {
options: {
separator: ';',
}
}

grunt: uglify css files with uglifyjs

I'm using grunt to uglify my static files (using grunt v0.4.0). I have configured it to uglify one file, but I can't figure out how to get it to do two files - despite reading this question and the usage examples.
Here's what I have currently:
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
mangle: true
},
build: {
src: 'dist/main.js',
dest: 'dist/main.min.js'
}
}
I'd like to uglify dist/main.css as well. How can I add it? I tried this, following the usage examples:
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
mangle: true
},
build: {
files: {
'dist/main.min.js': ['dist/main.js'],
'dist/main.min.css': ['dist/main.css']
}
}
}
But this gives me the following error:
WARN: ERROR: Unexpected token: punc ({) [dist/main.css:7,41]
Warning: Uglification failed. Use --force to continue.
Aborted due to warnings.
Seems like it's choking on the first { - why would that happen? It is valid CSS.
Uglify is for Javascript not CSS. Try using http://github.com/gruntjs/grunt-contrib-cssmin to minify CSS using Grunt.
Uglify is for Javascript only, but YUI Compressor can do both Javascript and CSS: YUI Compressor
There is a similar solution called UglifyCSS (https://github.com/fmarcia/UglifyCSS):
shell: uglifycss "source.css" > "output.min.css"
Where behaves much like UglifyJS.

Resources