I am using grunt with cssmin to minify and concatenate css files.
Css files are well concatenated and minified but when I try to watch the non minified files in chrome dev tools under 'Sources' tab, files appears empty.
Here is my cssmin task:
cssmin: {
options: {
report: 'gzip',
keepSpecialComments: 0,
sourceMap: true,
outputSourceFiles: true
},
target: {
files: {
'web/assets/dist/css/vendors.min.css': [
'bower_components/bootstrap/dist/css/bootstrap.min.css',
'bower_components/chosen/chosen.min.css',
'bower_components/slabText/css/slabtext.css',
'bower_components/video.js/dist/video-js.css',
'bower_components/video.js/dist/video-js.css'
],
'web/assets/dist/css/app.min.css': [
'app/Resources/assets/css/jumbotron-narrow.css',
'app/Resources/assets/css/custom.css',
],
}
}
},
Source map setting is enabled under chrome.
web/assets/dist/css/app.min.css.map looks like this:
{
"version":3,
"sources":["app/Resources/assets/css/jumbotron-narrow.css","app/Resources/assets/css/custom.css"],
"names":[],
"mappings":"AAeA,QAdA,KAeI,eAAgB,KADpB,QA6BA,WAEI,cAAe,IAAI,MAAM,QA7C7B,KACI,YAAa,KCUb,YAAa,eAAkB,WDHnC,QAFA,QACA,WAEI,cAAe,KACf,aAAc,KASlB,WACI,WAAY,EACZ,cAAe,EACf,YAAa,KAIjB,QACI,YAAa,KACb,MAAO,KACP,WAAY,IAAI,MAAM,QAI1B,yBACI,WACI,UAAW,OAGnB,qBACI,OAAQ,KAAK,EAIjB,WACI,WAAY,OAGhB,gBACI,QAAS,KAAK,KACd,UAAW,KAIf,WACI,OAAQ,KAAK,EAEjB,gBACI,WAAY,KAIhB,oCAII,QAFA,QACA,WAEI,cAAe,EACf,aAAc,EAGlB,QACI,cAAe,KAGnB,WACI,cAAe,GC3EvB,WACI,YAAa,eACb,IAAK,iCAAkC,mBAG3C,WACI,YAAa,YACb,IAAK,8BAA+B,mBAOxC,GACI,WAAY,KACZ,eAAgB,UAChB,YAAa,EACb,YAAa,YAAe,WAC5B,YAAa,EAAI,EAAI,IAAI,KAG7B,4BACI,QAAS,MACT,YAAa,KACb,aAAc,KACd,cAAe,IAGnB,UACI,UAAW,MACX,WAAY,KAIhB,oBACI,MAAO,IAGX,sBACI,gBAAiB,KACjB,YAAa,EAGjB,cACI,aAAc,QAIlB,iCACI,QAAS"
}
Version from my package.json:
"grunt-contrib-cssmin": "^0.12.0",
What am I doing wrong?
Edit: Firstly, try specifying a root in your options of the Gruntfile.js as follows:
// ...
cssmin: {
options: {
// ...
root: 'web/assets/dist/css/' // <-- Add this too.
},
target: {
// ...
}
/...
The Issue
The sourceMap file that grunt-contrib-cssmin is generating is incorrectly specifying the paths in the sources Array. The resultant sourceMap should be as follows:
app.min.css.map
{
"version":3,
"sources":[
"../../../../app/Resources/assets/css/jumbotron-narrow.css",
"../../../../app/Resources/assets/css/custom.css"
],
"names":[],
"mappings":"AAeA,QAdA,KAeI,eAAgB,KADpB,QA6BA,WAEI,cAAe,IAAI,MAAM,QA7C7B,KACI,YAAa,KCUb,YAAa,eAAkB,WDHnC,QAFA,QACA,WAEI,cAAe,KACf,aAAc,KASlB,WACI,WAAY,EACZ,cAAe,EACf,YAAa,KAIjB,QACI,YAAa,KACb,MAAO,KACP,WAAY,IAAI,MAAM,QAI1B,yBACI,WACI,UAAW,OAGnB,qBACI,OAAQ,KAAK,EAIjB,WACI,WAAY,OAGhB,gBACI,QAAS,KAAK,KACd,UAAW,KAIf,WACI,OAAQ,KAAK,EAEjB,gBACI,WAAY,KAIhB,oCAII,QAFA,QACA,WAEI,cAAe,EACf,aAAc,EAGlB,QACI,cAAe,KAGnB,WACI,cAAe,GC3EvB,WACI,YAAa,eACb,IAAK,iCAAkC,mBAG3C,WACI,YAAa,YACb,IAAK,8BAA+B,mBAOxC,GACI,WAAY,KACZ,eAAgB,UAChB,YAAa,EACb,YAAa,YAAe,WAC5B,YAAa,EAAI,EAAI,IAAI,KAG7B,4BACI,QAAS,MACT,YAAa,KACb,aAAc,KACd,cAAe,IAGnB,UACI,UAAW,MACX,WAAY,KAIhB,oBACI,MAAO,IAGX,sBACI,gBAAiB,KACjB,YAAa,EAGjB,cACI,aAAc,QAIlB,iCACI,QAAS"
}
Note the sourceRoot prefixes ../../../../ added to each path in the sources Array.
In the SourceMap Specification a section reads:
Resolving Sources
If the sources are not absolute URLs after prepending of the “sourceRoot”, the sources are resolved relative to the SourceMap (like resolving script src in a html document).
If specifying a root path, (as initially mentioned), does not resolve the issue then it indicates that this part of the specification is not being honoured by grunt-contrib-cssmin.
Alternate Solution
If the initial suggested fix does not work then consider adding a custom Task to invoke a Function which fixes each sources path after the sourceMap(s) have been created by grunt-contrib-cssmin.
You could do something like this:
Gruntfile.js
module.exports = function (grunt) {
grunt.initConfig( {
cssmin: {
options: {
report: 'gzip',
keepSpecialComments: 0,
sourceMap: true,
outputSourceFiles: true
},
target: {
files: {
'web/assets/dist/css/vendors.min.css': [
'bower_components/bootstrap/dist/css/bootstrap.min.css',
'bower_components/chosen/chosen.min.css',
'bower_components/slabText/css/slabtext.css',
'bower_components/video.js/dist/video-js.css'
],
'web/assets/dist/css/app.min.css': [
'app/Resources/assets/css/jumbotron-narrow.css',
'app/Resources/assets/css/custom.css'
]
}
}
}
});
/**
* Helper function prefixes sources paths in sourceMap files with a sourceRoot.
*
* `grunt-contrib-cssmin` does not apply the correct sourceRoot for each
* path in the `sources` Array. See github issue #248 for further info:
* (https://github.com/gruntjs/grunt-contrib-cssmin/issues/248)
*
* #param {String} filePath - The path to the sourceMap to fix.
* #param {String} sourceRootPrefix - The sourceRoot prefix e.g. ../../
*/
function prefixSourceMap(filePath, sourceRootPrefix) {
var json = grunt.file.readJSON(filePath);
json.sources = json.sources.map(function (_path) {
return sourceRootPrefix + _path;
});
grunt.file.write(filePath, JSON.stringify(json));
}
// Register Task to invoke function for fixing paths in each sourceMap file.
grunt.registerTask('fixSourceMaps', 'Fix paths in each sourceMap', function () {
prefixSourceMap('web/assets/dist/css/vendors.min.css.map', '../../../../');
prefixSourceMap('web/assets/dist/css/app.min.css.map', '../../../../');
});
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.registerTask("default", [
'cssmin',
'fixSourceMaps' // <-- Must be after cssmin tasks.
]);
};
Notes
The the custom grunt.registertask named fixSourceMaps invokes the prefixSourceMap function for each sourceMap file to fix.
Two arguments are passed to the prefixSourceMap function, namely:
filePath - The path to the sourceMap to fix.
sourceRootPrefix - The sourceRoot prefix e.g. ../../
For fixing both sourceMap files (vendors.min.css.map and app.min.css.map) the sourceRootPrefix argument is specified as ../../../../ - This is specified as four levels due to the relationship between the resultant .min.css file and it's location to the original unminified source .css file within your directory structure.
If you were to add another set of .css files to minify to your cssmin.target.files Task, in which the relationship between the resultant .min.css file and the unminified source .css file was not four levels, you will need to specify a different sourceRootPrefix value.
For example, lets say in cssmin.target.files the following css is to be minified:
// ...
target: {
files: {
//...
'web/assets/quux.min.css': [ // <-- Two levels deep
'path/to/file/foo.css',
'path/to/file/baz.css'
],
// ...
}
}
// ...
As the resultant quux.min.css is saved in the directory two levels deep then the sourceRootPrefix argument is passed to the prefixSoureMap functions as '../../'. For example:
//...
grunt.registerTask('fixSourceMaps', 'Fix paths in each sourceMap', function () {
prefixSourceMap('web/assets/quux.min.css.map', '../../');
//...
});
//...
as explained in comment above, there was 2 issues in my Gruntfile :
missing root directive as explained by #RobC
original assets were not accessible by the webserver, so I moved them in a location under the web root of my virtualhost. In my case web/assets. Here is my cssmin task that is now working:
cssmin: {
options: {
root: 'web/assets/dist/css/',
report: 'gzip',
keepSpecialComments: 0,
sourceMap: true,
outputSourceFiles: true
},
target: {
files: {
'web/assets/dist/css/app.min.css': [
'web/assets/css/jumbotron-narrow.css',
'web/assets/css/custom.css',
],
}
}
},
How should I be using requirejs-text which is installed via bower? I am supposed to put it in baseUrl but wonder if I could use it from components/requirejs-text/? Whats the best practice?
Define the path to the plugin in the config:
requirejs.config({
paths: {
"text" : "components/requirejs-text/text"
}
},
And use it in your module as documented on https://github.com/requirejs/text:
require(["some/module", "text!some/module.html", "text!some/module.css"],
function(module, html, css) {
//the html variable will be the text
//of the some/module.html file
//the css variable will be the text
//of the some/module.css file.
}
);
You can use also technically use the plugin without the path definition in the requirejs.config, but this is propbably not best practice:
require(["your_path_to_the_plugin_from_baseurl/without_js_at_the_end!some/textfile"],
function(yourTextfile) {
}
);
in PROJECT_APP/bower.js add this line under the dependencies section:
"requirejs": "~2.1.8",
"requirejs-text":"~2.0.10", // this is new
"qunit": "~1.12.0",
then run bower install, it should install this plugin and display at the end a path such as requirejs-text#2.0.10 vendor/bower/requirejs-text (depends on your configuration).
Finally, in the config.js file, add this line under
require.config({
paths: {
// Make vendor easier to access.
"vendor": "../vendor",
// Almond is used to lighten the output filesize.
"almond": "../vendor/bower/almond/almond",
// add the requirejs text plugin here
"text" : "../vendor/bower/requirejs-text/text",
// Opt for Lo-Dash Underscore compatibility build over Underscore.
"underscore": "../vendor/bower/lodash/dist/lodash.underscore",
// Map remaining vendor dependencies.
"jquery": "../vendor/bower/jquery/jquery",
"backbone": "../vendor/bower/backbone/backbone"
}
});
Then to use it, simply require it, in this case you can access it with the template variable
define([
// These are path alias that we configured in our bootstrap
'app', // general app variables
'jquery', // lib/jquery/jquery
'underscore', // lib/underscore/underscore
'backbone', // lib/backbone/backbone
'text!templates/books.html' // use the plugin to import a template
], function(app,$, _, Backbone, template){ // don't forget to define it !
This is how I have install requirejs-text using bower
In your project's bower.json file:
{
"name":"{{YOUR PROJECT NAME}}",
"version":"{{YOUR PROJECT VERSION}}",
"dependencies":{
"requirejs-text":"2.0.6"
}
}