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',
],
}
}
},
When running an application that is built using webpack 2, sourcemaps are detected in chrome but original source is not loaded.
I'm using webpack beta21.
These files used to be detected automatically, ie when a breakpoint was put in the the output from webpack js file, the source view would jump to the original source input to webpack. But now I am stuck with this screen:
config:
var path = require("path");
var webpack = require("webpack");
var WebpackBuildNotifierPlugin = require('webpack-build-notifier');
const PATHS = {
app: path.join(__dirname, '../client'),
build: path.join(__dirname, '../public')
};
module.exports = {
entry: {
app: PATHS.app + '/app.js'
},
output: {
path: PATHS.build,
filename: '[name].js'
},
devtool: "source-map",
module: {
loaders: [
{
test: /\.js?$/,
loader: 'babel-loader',
include: [
path.resolve(__dirname, 'client'),
],
exclude: /node_modules/
},
{
test: /\.css/,
loader: "style!css"
}
]
},
resolve: {
// you can now require('file') instead of require('file.js')
extensions: ['', '.js', '.json']
} ,
plugins: [
new WebpackBuildNotifierPlugin()
]
};
Generated files with source maps won't automatically redirect to their original files, because there's potentially a 1-to-many relationship.
If you see the message Source Map Detected, the original file should already appear on the side file tree or the file explorer via Crl + P. If you don't know the original file name, you can open the source map file itself.
The source map path can be identified by a //# sourceMappingURL= comment or the X-SourceMap header:
Open up the source map via url and look for the sources property for the original file name:
The original file should be visible in the sources panel:
If you don't see the message Source Map Detected
You can manually add an external source map by right clicking and selecting Add Source Map:
Additional Resources
If that still doesn't work, you can try a Source Map Validator
For webpack specifically, you can configure the devtool property
If you're mapping to a workspace, that means you already have the source code. Including the source code in your source map is creating an unnecessary redundancy.
Use nosources-source-map instead.
The issue with external source maps was fixed in Chrome 52 but it looks like you've got your devtool set differently from mine, I use:
devtool: '#source-maps'
How are you building your source? If you're running with -d it will switch to inline source maps
Due to a FUBAR directory organization in a project, I have spent some time re-organizing JS scripts on said project. The project uses requirejs and was functioning wonderfully before the re-org. However, now nothing loads when called or compiles (we use the r.js optimizer) when run -- though compiling completes without complaint. I have checked, double-checked, triple-checked, and now given in to asking for another set of eyes here on Stack Overflow.
Using RequireJS: 2.1.4 and r.js 2.1.4
The following is my configuration:
build-js.js (used for optimizer)
var requirejs = require('requirejs');
var config = {
baseUrl: './public/js',
mainConfigFile: './public/js/config/config.js',
paths: {
'requireLib': 'library/require'
},
out: ".public/js/minified/main.js",
name: "minified/main",
wrap: false,
preserveLicenseComments: false,
deps: ["app/main","modules/movie","modules/theatre"]
};
requirejs.optimize(config);
config.js
// Set the require.js configuration for your application.
require.config({
paths: {
// JavaScript folders
libs: "library",
plugins: "plugin",
app: "app",
adminlibs: "../adminassets/js/plugins/ui",
// Libraries
jquery: "library/jquery",
jqcookie: "library/jquery.cookie",
jqui: "../adminassets/js/plugins/ui/jquery-ui-1.10.0.custom.min",
jqezmark: "library/jquery.ezmark",
jqcolor: "library/jquery.color",
underscore: "library/underscore-amdjs",
backbone: "library/backbone-amdjs",
chosen: "library/chosen.jquery",
moment: "library/moment",
// Site Components
site: "app/site",
sitediscussion: "app/site-discussion",
namespace: "app/namespace",
// Plugins
text: "plugin/text",
async: "plugin/async",
use: "plugin/use",
datetimepicker: "../adminassets/js/plugins/ui/jquery.datetimepicker",
ajaxfileupload: "../adminassets/js/plugins/uploader/jquery.ajaxfileupload"
},
shim: {
'chosen': ['jquery'],
'jqcookie': ['jquery'],
'jqui': ['jquery'],
'jqezmark': ['jquery'],
'jqcolor': ['jquery'],
'site': {
deps: ['jquery','jqezmark','chosen','underscore','namespace','jqui','jqcookie'],
exports: 'site'
},
'sitediscussion': {
deps: ['jquery', 'underscore'],
exports: 'sitediscussion'
},
'jquifull' : ['jquery'],
'datetimepicker' : ['jqui'],
'ajaxfileupload' : ['jquery'],
'backbone': ['underscore','jquery']
},
// Initialize the application with the main application file
deps: ["app/main"]
});
File structure is as follows:
{site-root}/public/js
Which contains directories:
app
config
library
minified
modules
plugin
templates
All files listed above in build-js and config.js are confirmed to be in the expected folders.
requirejs is called as follows:
On dev machines (which I'm currently testing the setup on):
data-main="/js/config/config" src="/js/library/require.js"
On production (currently the minified/main file is not even being created, though it should be)
data-main="/js/minified/main" src="/js/library/require.js"
Can anyone see what I may be doing wrong? Again, there have been no changes to the site proper, the javascript, etc except in the two files (build-js.js and config.js) listed above. The only changes are that files have been physically moved in the directory structure. As a result, I'm nearly positive that I have a pathing issue somewhere, but I cannot seem to find it. Help?
Resolution has been found. I was referencing my configuration file through the data-main attribute in the requirejs include script tag at "/js/config/config". Though I declared a base-path of /public/js, the system was still attempting to use /js/config/ as my base path ( as stated in requirejs documentation that it will base-path based off your data-main attribute if a base path is not otherwise declared ). I moved my config.js file to /js and changed data-main to /js/config and now all paths are working appropriately, referencing base-path /js.
A side-note is that I did not notice the failure of files to load because of my use of Zend Framework and error handling. There were no 404 Errors and the Network tab of my dev-tools showed success in loading all .js files ... it was only when I looked at the response-content of those files that I found they were spitting out PHP error logs rather than .js content.