Configure Grunt File Name Matching for Files with Multiple Dots - gruntjs

I just started using grunt, and love it.
I keep running into an issue that seems like it might be pretty common.
Here it is. I have files named so that words after a dot are something like classes. eg:
layout.coffee
layout.blog.coffee
layout.site.coffee
My grunt task is configured to watch these files and translate them to js like this:
coffee:
dev:
files: [
expand: true
cwd: "<%= yeoman.app %>"
src: ["**/*.coffee"]
dest: "<%= yeoman.dev %>"
ext: ".js"
]
The problem, I think, is that using ext makes the target for all three .coffee files the destination file layout.js, which isn't the intention.
Is there a nice way to configure grunt file mapping for filenames with multiple dots?
Right now I have to change my naming convention to use - instead of ., which is a drag :(

Note that there is another option "extDot" that you can use to specify after which dot the ext should apply (first or last):
E.g.
files: [{
expand: true,
src: ['*.js','!*min.js'],
dest: 'js',
cwd: 'js',
ext: '.min.js',
extDot: 'last'
}]

Take a look at the "Building the files object dynamically" section of Configuring Tasks.
Instead of specifying ext, you can specify rename which is a function that lets you create your own mapping for the file names.
The problem you are running into was brought up as an issue on github and the answer from the grunt folks was that the "extension" of a file should be everything after the first "." instead of the last.
Hope that helps you!

That's the workaround I'm using in my projects:
uglify : {
build : {
src : ['**/*.js', '!*.min.js'],
cwd : 'js/',
dest : 'js/',
expand : true,
rename : function (dest, src) {
var folder = src.substring(0, src.lastIndexOf('/'));
var filename = src.substring(src.lastIndexOf('/'), src.length);
filename = filename.substring(0, filename.lastIndexOf('.'));
return dest + folder + filename + '.min.js';
}
}
}
When the filename is like jquery.2.0.3.js then after minifying that it will be jquery.2.0.3.min.js.

Related

extra c: added to destination path on windows ((Error code: ENOENT))

Using latest version of grunt if we try to work like copying
copy: {
main: {
files: [
{ expand: true
src: ['/dev/war archive/latestfile/**/*.txt'],
dest: '/fernando/backups/pbuse/war',
filter :'isFile'
}
]
}
}
This will result in Error: Unable to create directory "C:\harikishore\backups\war\C:" (Error code: ENOENT)
In latest version of grunt we need to add the cwd(currentworkingdirectory) where the provided src is located for the action otherwise grunt-action will consider the actual system path included with src,so while creating destination will try to create the systempath which will result in the above error so it will work if change the code as below:
copy: {
main: {
files: [
{ expand: true,
cwd : '/dev/war archive/latestfile/'
src: ['**/*.txt'],
dest: '/fernando/backups/pbuse/war',
filter :'isFile'
}
]
}
}
So,now it will start the dest folder creation from src instead of system path included
Alternative: adding flaten:true property
This will allow us to pass the action since we are not creating the inner folder structure of src in dest just copying all the files and dumping in single outer folder.
If we need inner folder structure of src in dest also then we must need cwd

How to create source maps dynamically with grunt-closurecompiler

I can't get it to work. name_of_current_file needs to somehow be replaced with name of the current file being processed. It seems to me like the options property is only evaluated once and reused for each file.
closurecompiler: {
dev: {
files:[{
expand: true,
flatten: true,
cwd: 'www',
src: ['src/js/*.js', '!src/js/*.min.js'],
dest: 'www/build/js/',
ext: '.min.js',
}],
options: {
// Any options supported by Closure Compiler, for example:
"compilation_level": "ADVANCED_OPTIMIZATIONS",
"create_source_map": name_of_current_file+'.map',
// Plus a simultaneous processes limit
"max_processes": 4,
}
},
}
You can use the replacement variable %outname% in your source map naming.
"create_source_map": '%outname%.map'
Also, make sure you are using the officially supported Grunt Plugin.

Grunt-string-replace not working

I have an app folder where I want to replace http://localhost:8000 for http://fomoapp-melbourne.rhcloud.com in two files: companies-list.component.ts and events-list.component.ts. I am trying to use grunt-replace-string plugin and it seemingly runs successfully with green Done result and no errors, but no replacement happens.
Here is how Gruntfile.js looks like:
module.exports = function(grunt){
[
'grunt-string-replace',
].forEach(function(task){
grunt.loadNpmTasks(task);
});
// configure plugins
grunt.initConfig({
'string-replace': {
dist: {
files: {
'./app/': ['companies-list.component.ts','events-list.component.ts'],
},
options: {
replacements: [{
pattern: 'http://localhost:8000',
replacement: 'http://fomoapp-melbourne.rhcloud.com',
}]
}
}
},
});
// register tasks
grunt.registerTask('default', ['string-replace']);
};
The Grunt Files object is for specifying a mapping of source files to destination files. The purpose of this mapping is to tell Grunt to get the contents of the files in source, do something to the contents, and then write the response to a new file in the destination folder.
It looks to me from your configuration that you want Grunt to rewrite two files in the app/ directory. This is not going to work. I will bet that if you run grunt with the verbose option, grunt --verbose, your output will contain the following:
Files: [no src] -> ./app/
This is because Grunt cannot find the source files because you need to specify their relative paths.
It's up to you how you want to structure your app, but you might want to have a src/ folder and a dist/ folder under app/. If you choose to build your files objects dynamically, your config might look something like this:
files: [{
expand: true,
cwd: './app/src/',
dest: './app/dest/',
src: ['companies-list.component.ts', 'events-list.component.ts']
}]
Additionally, the documentation for grunt-string-replace states:
If the pattern is a string, only the first occurrence will be replaced, as stated on String.prototype.replace.
This means that if you want multiple instances of your string to be replaced, you must provide a Regular Expression literal. For example:
replacements: [{
pattern: /http:\/\/localhost:8000/g,
replacement: 'http://fomoapp-melbourne.rhcloud.com'
}]

grunt-contrib-jade compiling to single JS with cwd

I am trying to compile multiple jade templates into single JS file using grunt-contrib-jade. Problem I'm facing is that with full path to templates, I get function names with full path. I want to avoid that, so I tried using cwd (without expand). This ended up with the following:
>> Source file "test.jade" not found.
>> Source file "test2.jade" not found.
Is there any way I could achieve what I plan? My grunt config for that task is as following:
jade: {
js: {
options: {
client: true,
amd: true
},
files: [ {
cwd: 'js/views/',
src: ['*.jade'],
dest: 'js/tmp/templates.js'
} ]
}
},
Thanks in advice,
Dracco
Silly me, didn't fully read the documentation of the plugin :(.
The solution is trivial, using the processName option:
options: {
client: true,
amd: true,
processName: function(path) {
var pathChunks = path.split('.')[0].split('/');
return pathChunks[pathChunks.length - 1];
}
}

Using grunt to concat many files from many dirs into single renamed file in new directory

I have an Angular project with potentially many modules. Each module has it's own directory with subdirectories for controllers, directives, services, etc. Something like this:
src
|-- js
|-- modules
|-- moduleOne
| module.js
|-- controllers
| listController.js
| detailController.js
|-- directives
| listItem.js
| summaryWidget.js
|-- filters
|-- services
| moduleService.js
My build essentially bundles and compiles files from src/ and puts into dev/, then minifies the files in dev/ and moves into prod/. During dev, the server points to the dev/ folder and in production, the server points to the prod/ folder (also why the files are ending in .min.js even though they are only compiled/concated). This process is working well.
Currently, my concat task is grabbing all the files in moduleOne/ and creating a single moduleOne.js file in my dev directory. This is what I want to happen, but more dynamically:
concat: {
modules: {
files: {
"dev/js/modules/moduleOne.min.js": [
"src/js/modules/moduleOne/*.js",
"src/js/modules/moduleOne/**/*.js"
],
"dev/js/modules/moduleTwo.min.js": [
"src/js/modules/moduleTwo/*.js",
"src/js/modules/moduleTwo/**/*.js"
]
}
}
}
The problem is that I have to do this for every module, but don't think I would need to.
I tried doing the following because it's sort of what I want to do:
concat: {
modules: {
files: [{
expand: true,
cwd: "src/js/modules",
src: "**/*.js",
dest: "dev/js/modules",
ext: ".min.js"
}]
}
}
But the result was all my files and directory structure moved over from src/ to dev/. I basically used concat to do a copy, not helpful.
I'd like to do something like this:
concat: {
modules: {
files: [{
expand: true,
cwd: "src/js/modules",
src: "**/*.js",
dest: "dev/js/modules/<foldername>.min.js", <- how do I achieve this?
}]
}
}
I've been reading a lot, but it seems that I only get close to finding the answer and am having trouble putting the concepts together. A lot of what I find is just single files into a new directory, with a rename. I'd like multiple files to single file into new directory with a rename. Cuz that's how I roll :)
So, I found the answer I was looking for.
This SO post was basically the same question with a good answer. Unfortunately it didn't come up when I was creating my question or else you wouldn't be reading this.
There was a slight tweak to my needs. I needed to do it dynamically per module instead of just one compile.js file so my final code is as follows, placed just after my initConfig():
grunt.registerTask("prepareModules", "Finds and prepares modules for concatenation.", function() {
// get all module directories
grunt.file.expand("src/js/modules/*").forEach(function (dir) {
// get the module name from the directory name
var dirName = dir.substr(dir.lastIndexOf('/')+1);
// get the current concat object from initConfig
var concat = grunt.config.get('concat') || {};
// create a subtask for each module, find all src files
// and combine into a single js file per module
concat[dirName] = {
src: [dir + '/**/*.js'],
dest: 'dev/js/modules/' + dirName + '.min.js'
};
// add module subtasks to the concat task in initConfig
grunt.config.set('concat', concat);
});
});
// the default task
grunt.registerTask("default", ["sass", "ngtemplates", "prepareModules", "concat", "uglify", "cssmin"]);
This essentially makes my concat task look like it did when I was hand coding it, but just a little simpler (and scalable!).
concat: {
...
moduleOne: {
src: "src/js/modules/moduleOne/**/*.js",
dest: "dev/js/modules/moduleOne.min.js"
},
moduleTwo:{
src: "src/js/modules/moduleTwo/**/*.js",
dest: "dev/js/modules/moduleTwo.min.js"
}
}
Another deviation I made from the SO post was that I chose not to have prepareModules run concat on it's own when it was done. My default task (which watch is setup to run during dev) still does all my processing.
This leaves me with the following structure, ready for minification into prod/:
| dev
| js
| modules
|-- moduleOne.min.js
|-- moduleTwo.min.js

Resources