Why do we need to use grunt - useminPrepare - gruntjs

I'm a bit confused of why the yeoman angular generator has the concat tasks inside the useminPrepare task since the concat and uglify are run later in the build task.
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
grunt.registerTask('build', [
'clean:dist',
'bowerInstall',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngmin',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'rev',
'usemin',
'htmlmin'
]);
can someone enlighten me?

The useminPrepare task does not actually do any minification, but instead it parses HTML and sets the appopriate configuration for other tasks. For example, if you have this in your HTML:
<!-- build:js js/app.js -->
<script src="js/app.js"></script>
<script src="js/controllers/thing-controller.js"></script>
<script src="js/models/thing-model.js"></script>
<script src="js/views/thing-view.js"></script>
<!-- endbuild -->
The useminPrepare task will set the following configuration:
{
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']
}
}
And the block in the HTML will then be replaced with with:
<script src="dist/js/app.js"></script>
For more information, see https://github.com/yeoman/grunt-usemin.

Related

Images paths is replaced in html file but not in js files

I am new to Grunt and all the tasks so bear with me on this one. I'm developing an AngularJS application, that I initially created through Yeoman. Since theres lot's of views I thought it would be a good idea to include all the views in the templatecache. So I installed html2js and configured it according to their GitHub read. It's working almost perfectly, except from one thing. My templates contain some references to local images. When running grunt build all those images's names are getting changed by revfile. Looking at the dist/views folder with all the templates, I can see that the paths is correct (the path has been replaced with the new one). However, those changes to the paths doesn't make it into the js-file that html2js generates.
How can I make Grunt replace the paths correctly in the generated html2js js-file as well? Here is the grunt initConfig parts that I think is relevant
filerev: {
dist: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/fonts/*'
]
}
},
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
// Performs rewrites based on filerev and the useminPrepare configuration
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>', '<%= yeoman.dist %>/images']
}
},
****************************
grunt.registerTask('build', [
'clean:dist',
'wiredep',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'html2js:main',
'concat',
'ngAnnotate',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'filerev',
'usemin',
'htmlmin'
]);
May I suggest that you use grunt-angular-templates instead? It is designed precisely to insert views into the $templateCache.
I have never had any problems with relative paths.
You can even pair it with https://github.com/mgcrea/grunt-nginclude to inline "partials".

how to prevent usemin from overwriting original index.html file

I'm using usemin and I generally like it, but I really dislike the fact that usemin overwrites my original index.html file. I have a pretty typical setup in my Gruntfile:
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
root: '<%= yeoman.root %>',
staging: '<%= yeoman.tmp %>',
dest: '<%= yeoman.dist %>',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
Whenever I build using grunt everything in the end gets dumped into a dist directory. Most other tasks that need to do 'temporary' modifications copy and modify files in a .tmp directory.
usemin mucks with the actual index.html file though. I particularly don't like this because it makes Github think the file has changed every time I check in new code.
Is there a way to tell usemin to use the .tmp directory like most other grunt plugins?
I do specify my temp directory with:
staging: '<%= yeoman.tmp %>'
but that doesn't seem to prevent the index.html file from being overwritten.
Thanks.
UPDATE (per the comment below)
Here is the usemin task itself:
// Performs rewrites based on filerev and the useminPrepare configuration
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/images']
}
},
and here is the grunt task that uses both useminPrepare and usemin:
grunt.registerTask('build', [
'clean:dist',
'wiredep',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngAnnotate',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'filerev',
'usemin',
'htmlmin',
'bridge:dist'
]);
just do not perform filerev task. This is the task that modify the original html files.

usemin and rewriting urls of images in vendor CSS files using Grunt

grunt-usemin helps me to transform
<link href="/dependencies/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="/dependencies/nanoscroller/bin/css/nanoscroller.css" rel="stylesheet" />
<link href="/dependencies/dropzone/downloads/css/dropzone.css" rel="stylesheet" />
to a perfectly combined and minified js:
<link href="scripts/8e1991c7.libraries.js" rel="stylesheet" />
After concat, cssmin and uglify I have a almost perfect folder structure except for images and their locations.
Here is my problem:
All these vendor's css files are including image locations. The bad thing is that all of them are sharing different kind of locations. Some of them are using images inside css folder whereas others are using inside img folder.
How can I configure grunt usemin to rewrite all images urls?
1) Rev images. Add paths of images into rev task.
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/static/scripts/{,*/}*.js',
'<%= yeoman.dist %>/static/styles/{,*/}*.css',
'<%= yeoman.dist %>/static/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
]
}
}
}
2) Add paths of file which are including image locations into usemin task.
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/static/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist%>/static/images'],
}
}
3) Run grunt.
I've solved the problem using the following.
useminPrepare: {
html: 'src/index.html',
options: {
dest: 'build',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
cssmin: {
options: {
root: 'src'
}
}
First, we are overriding useminPrepare's flow, removing the concat task from the css flows. This is needed because concat will destroy relative path information. Since cssmin will itself concat multiple files together, the sepearte concat task is only harmful. (https://github.com/yeoman/grunt-usemin/issues/225)
Lastly, we are telling cssmin where the "root" of your project is from the Gruntfile. This helps cssmin rewrite the relative urls it finds relative to this "root" directory.
What fixed the CSS background-image revving for me was to add a CSS pattern in options, which finds all asset references in the CSS and replaces them with the revved assets.
// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
...
...
options: {
...
...
// This is so we update image references in our ng-templates
patterns: {
js: [
[/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images']
],
css: [
[/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the CSS to reference our revved images']
]
}
}
},
I did a little digging around and found a pair of tasks that look like they'll get the job done: https://github.com/yeoman/grunt-filerev & https://github.com/richardbolt/grunt-cssurlrev. The only problem with this is that you'll have to configure the paths inside your Gruntfile manually, like so:
grunt.initConfig({
filerev: {
images: {
src: ['img1.png', 'img2.png'],
dest: 'tmp'
}
},
cssurlrev: {
dist: {
src: ['public/css/*.css']
},
}
});
To my knowledge there isn't a plugin that does this task automatically.
I had to implement a new task. This is my preliminary implementation.
grunt.registerMultiTask('rewriteCssUrl', 'rewrite url in css', function () {
var options = this.options({
assets: grunt.filerev ? grunt.filerev.summary : {},
postFilter: function identity(input){ return input}
});
var self = this;
var assets = options.assets;
self.filesSrc.forEach(function (file) {
var css = grunt.file.read(file);
var original = css;
css = css.replace(/(?:src=|url\(\s*)['"]?([^'"\)]+)['"]?\s*\)?/gm, function (match, src) {
var key = path.join(path.dirname(file), src);
var asset = assets[path.normalize(key)];
var val = options.postFilter(asset);
return match.replace(src, val || match);
});
if(original !== css) {
grunt.log.writeln('✔ '.green + file + (' was changed.').grey);
grunt.file.write(file, css);
}
});
});
My approach to this problem was to basically create a separate styles/select2/select2.css for each vendor style, and then all relevant images can be copied by Grunt into styles/select2 (without having to worry about relative paths or overwriting etc) as part of the script. That is:
app/index.html
<!-- build:css(.tmp) styles/select2/select2.css -->
<link rel="stylesheet" href="bower_components/select2/select2.css">
<!-- endbuild -->
Gruntfile.js
Add a new copy task that will copy over vendor styles into the .tmp directory before they are minimised with cssmin:
copy: {
// this copies bower_components/*.css into .tmp so they can be compiled
styles: {
expand: true,
cwd: '<%= yeoman.app %>',
dest: '.tmp/',
src: [
'styles/{,*/}*.css',
'bower_components/**/*.css'
]
},
dist: ...
And then once they are minimised, copy over the relevant assets (which in this case I'm assuming is just PNG and GIF images):
// and once we have compiled all of our stylesheets, we need to also copy over any necessary image files
distAssets: {
expand: true,
cwd: '<%= yeoman.app %>/bower_components',
dest: '<%= yeoman.dist %>/styles',
src: [
'**/*.png',
'**/*.gif'
]
}
},
Finally, add the new tasks into the build task:
grunt.registerTask('build', [
'clean:dist',
'replace:dist',
'copy:styles', // -- added
'useminPrepare',
// ... etc ...
'copy',
'rev',
'usemin',
'copy:distAssets' // -- added
]);

Change the configuration of the task uglify dynamically

I need to change configuration of my uglify task for only minify file as needed (as explained here for the jshint task : https://github.com/gruntjs/grunt-contrib-watch#compiling-files-as-needed)
The modification works well for the jshint task but not for uglify, i think the problem is the property path...
Any help would be appreciated ;)
Here is my Gruntfile.js :
module.exports = function (grunt) {
grunt.initConfig({
// define source files and their destinations
jshint: {
all: ['dev/**/*.js'],
},
uglify: {
dynamic_mappings: {
// Grunt will search for "**/*.js" under "dev/" when the "minify" task
// runs and build the appropriate src-dest file mappings then, so you
// don't need to update the Gruntfile when files are added or removed.
files: [{
expand: true, // Enable dynamic expansion.
cwd: 'dev/', // Src matches are relative to this path.
src: ['**/*.js'], // Actual pattern(s) to match.
dest: 'build', // Destination path prefix.
ext: '.min.js', // Dest filepaths will have this extension.
},
],
}
}
watch: {
options: { spawn: false },
js: { files: 'dev/**/*.js', tasks: [ 'uglify' ] },
}
});
// load plugins
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
// default task
grunt.registerTask('default', [ 'watch' ]);
grunt.event.on('watch', function(action, filepath) {
grunt.config(['jshint', 'all'], filepath);
grunt.config('uglify.dynamic_mappings.files', [{src: filepath }]);
});
};
The line
grunt.config('uglify.dynamic_mappings.files', [{src: filepath }]);
Is completely replacing the original configuration for uglify.dynamic_mappings.files
Instead try including the other original parameters along with the new src: filepath
How to not minify already minified on each "grunt build" in yeoman
uglify: {
onlyScripts: {
files: [{
dest: '<%= yeoman.dist %>/scripts/scripts.js',
src: ['.tmp/concat/scripts/scripts.js']
}]
}
}
Also, now uglify will not copy your vendor.js from temporary folder, so add "vendorJS" section to "copy" task:
copy:
//...
vendorJS: {
expand: true,
cwd: '.tmp/concat/scripts/',
dest: '<%= yeoman.dist %>/scripts/',
src: 'vendor.js'
}
Then, in "build" task, set target of uglify to 'onlyScripts' and copy vendor.js:
grunt.registerTask('build', [
'jshint',
'clean:dist',
//'wiredep',
// ...
'useminPrepare',
//'concurrent:dist',
'autoprefixer',
'concat',
'ngAnnotate',
'copy:dist',
'cssmin',
'uglify:onlyScripts',
'copy:vendorJS',
// ...
]);
http://eugenioz.blogspot.in/2014/08/how-to-not-minify-already-minified-on.html

grunt-requirejs - how to optimize CSS?

I'm using Yeoman, and are trying to setup requirejs to optimise my CSS files.
I have this in my Gruntfile.js:
requirejs: {
css: {
options: {
optimizeCss: 'standard',
cssIn: 'app/styles/main.css',
out: 'app/styles/main.min.css'
}
}
}
When I run the build command I get an error:
grunt build
Running "requirejs:css" (requirejs) task
>> Error: TypeError: new path must be a string
>> at Object.fs.renameSync (fs.js:439:18)
Warning: Task "requirejs:css" failed
I'm not really sure what's happening there, or how to debug that.
Does anyone know what the problem could be?
Never mind, I worked it out.
The silly useminPrepare task that ships with Yeoman stuffs around with the grunt-requirejs configuration. Kind of annoying, esp. since the point of me wanting to use grunt-requirejs was because I didn't like how usemin worked to begin with.
UPDATE:
This is my configuration that works:
//index.html:
<!-- build:js scripts/scripts.js -->
<script data-main="scripts/main" src="components/requirejs/require.js"></script>
<!-- endbuild -->
//Gruntfile.js:
requirejs: {
js: {
options: {
baseUrl: '<%= yeoman.tmp %>/scripts',
out: '<%= yeoman.dist %>/scripts/scripts.js',
name: 'main',
optimize: 'none',
mainConfigFile: '<%= yeoman.app %>/scripts/main.js',
useStrict: true,
wrap: true
}
},
css: {
options: {
optimizeCss: 'standard',
cssIn: '<%= yeoman.app %>/styles/main.css',
out: '<%= yeoman.dist %>/styles/main.css'
}
}
},
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>'
}
},
usemin: {
html: '<%= yeoman.dist %>/index.html',
options: {
dirs: ['<%= yeoman.dist %>']
}
}
grunt.registerTask('build', [
'requirejs:js',
'requirejs:css',
'useminPrepare', //must be after requirejs:css as it breaks its config params
'usemin'
]);
NOTE: There is still an underlying bug in grunt-usemin where it (incorrectly) tries to alter the requirejs config for the requirejs:css configuration. I've reported that here

Resources