How to skip source parent directory using grunt uglify - gruntjs

src directory:
dir1
|-- 1.js
|-- 2.js
`-- sub-dir1
`-- 1.js
dest directory:
min
`-- dir1
|-- 1.min.js
|-- 2.min.js
`-- sub-dir1
`-- 1.min.js
My code snippet:
uglify: {
t2: {
options: {
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> */'
},
files: [{
expand: true,
src: ['dir1/**/*.js'],
dest: 'min',
rename: function (dst, src) {
return dst + '/' + src.replace('.js', '.min.js');
}
}]
}
}
But I want to skip source directory under destination directory, desired structure is:
min
|-- 1.min.js
|-- 2.min.js
`-- sub-dir1
`-- 1.min.js

There's a couple of ways to achieve this. Solution A (below) is the simplest and most commonly used.
Solution A
When building the files object dynamically you can utilize the cwd property. The description of the cwd property in the docs reads:
cwd All src matches are relative to (but don't include) this path.
Change your files property to the following:
// ...
files: [{
expand: true,
cwd: 'dir1/', // <-- Add this.
src: '**/*.js', // <-- Change your src glob to this.
dest: 'min',
rename: function (dst, src) {
return dst + '/' + src.replace('.js', '.min.js');
}
}]
// ...
Solution B
Another way, (without utilizing the cwd property), is to change your rename method to the following instead:
// ...
rename: function (dst, src) {
src = src.split('/');
src.shift();
src = src.join('/');
return dst + '/' + src.replace('.js', '.min.js');
}
// ...
The src = src.split('/'); part utilizes the String split() method with the / separator to split the src path into an array of individual path items.
The src.shift(); part utilizes the Array shift() method to remove the first element from the array (e.g. dir1).
The src = src.join('/') part utilizes the Array join() method with the / separator to form the new path as a String.

Related

Adapt dest folder to ** globbing pattern

I'm working with grunt-contrib-copy. I have this file tree:
`-- src
`-- model
|-- a4
| `-- public
| |-- css
| |-- img
| `-- js
|-- posters
| `-- public
| |-- css
| |-- img
| `-- js
`-- prints
`-- public
|-- css
|-- img
`-- js
I would like to copy the files in
src/model/**/public/img to dist/images/{1}/ where {1} is the folder name (a4, posters, prints... dynamic folders that are bound to change too), so:
src/model/a4/public/img/file.png -> dist/images/a4/file.png
Is there a way to specify that with grunt-contrib-copy (maybe the rename function?) or do I have to iterate manually over the files?
Right now this is what I have:
grunt.registerTask 'images-generate', ->
gruntCopyFiles.images = {
expand: true,
cwd: './src/model/',
src: ["**/public/img/*.png", "**/public/img/*.jpg"],
dest: "./dist/images/"
}
But this copies src/model/a4/public/img/file.png to dist/images/a4/public/img/file.png which is not what I want.
Any suggestion? Thanks!
Is there a way to specify that with grunt-contrib-copy (maybe the rename function?) or do I have to iterate manually over the files?
Utilizing the rename function is the way to achieve this. Glob patterns alone cannot meet your requirement, nor can the flatten option.
Something like the following also copies any subfolders which may potentially reside inside the source img folders:
gruntCopyFiles.images = {
expand: true,
cwd: 'src/model',
dest: 'dist/images',
src: '**/public/img/**/*.{png,jpg,gif}',
rename: function(dest, src) {
var items = src.split('/'),
baseIndex = items.indexOf('img') + 1,
subPath = items.slice(baseIndex, items.length).join('/');
return [dest, items[0], subPath].join('/');
}
}
Example:
src/model/a4/public/img/file.png --> dist/images/a4/file.png
src/model/a4/public/img/quux/file.jpg --> dist/images/a4/quux/file.jpg
Looks like you can use flatten to get stripped-down destination paths:
gruntCopyFiles.images = {
flatten: true,
expand: true,
cwd: './src/model/',
src: ["**/public/img/*.png", "**/public/img/*.jpg"],
dest: "./dist/images/"
}
From the docs:
flatten Remove all path parts from generated dest paths.

Grunt how to run task with different arguments

The source config example below processes files from src dir. There is src2 dir which also should be processed with the same tasks and putted to build2. What changes required in config.
module.exports = function (grunt) {
var saveLicense = require('uglify-save-license');
grunt.initConfig({
clean : {
build : {
src : ['build']
},
},
copy : {
files : {
cwd : 'src',
src : '**/*',
dest : 'build',
expand : true
}
},
...
Both grunt-contrib-copy and grunt-contrib-clean, like many other grunt plugins, allow multiple Targets to be specified in each Task.
For your scenario you can simply configure two Targets in the copy task (one Target to copy the src folder and another Target to copy the src2 folder).
You can also configure two Targets in the clean task (one Target to clean the build folder and another Target to clean the build2 folder).
Gruntfile.js
Your Gruntfile.js can be configured as ass follows:
module.exports = function(grunt) {
var saveLicense = require('uglify-save-license');
grunt.initConfig({
// The 'clean' task now includes two targets.
// named 'build1' and 'build2'
clean: {
build1: {
src: ['build']
},
build2: {
src: ['build2']
}
},
// The 'copy' task now includes two targets.
// named 'src1' and 'src2'
copy: {
src1: {
cwd: 'src',
src: '**/*',
dest: 'build',
expand: true
},
src2: {
cwd: 'src2',
src: '**/*',
dest: 'build2',
expand: true
}
}
// ...
});
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-clean');
// Registering the Targets in the Tasks....
grunt.registerTask('copySrc1', ['copy:src1']);
grunt.registerTask('cleanBuild1', ['clean:build1']);
grunt.registerTask('copySrc2', ['copy:src2']);
grunt.registerTask('cleanBuild2', ['clean:build2']);
grunt.registerTask('copyBoth', ['copy']);
grunt.registerTask('cleanBoth', ['clean']);
};
Running the Grunt Tasks
You'll notice that there are six calls to the .registerTask(...) function at the end of the snippet. Namely; copySrc1, cleanBuild1, copySrc2, cleanBuild2, copyBoth, and cleanBoth.
They allow you to run the following commands via your command line:
$ grunt copySrc1
(This will copy the src folder to the build folder)
$ grunt cleanBuild1
(This will clean the build folder)
$ grunt copySrc1
(This will copy the src2 folder to the build2 folder)
$ grunt cleanBuild2
(This will clean the build2 folder)
$ grunt copyBoth
(This will copy the src folder to the build folder and copy the src2 folder to the build2 folder)
$ grunt cleanBoth
(This will clean both the build and build2 folders)
Notes
You probably only need to keep the two .registerTask(...) functions as follows:
grunt.registerTask('copyBoth', ['copy']);
grunt.registerTask('cleanBoth', ['clean']);
However, I included the other four .registerTask(...) functions as they demonstrate how you can call a single Target inside a Task using the semicolon notation (:). For example:
grunt.registerTask('copySrc1', ['copy:src1']);
In the above snippet the ['copy:src1'] part simply runs only the Target named src1 inside the copy Task.
Whereas:
grunt.registerTask('copyBoth', ['copy']);
... does not reference any Targets in the copy task, (i.e. no semicolon notation is used), therefore all Targets will be run.
To further understand Tasks, Targets, you can read my answer to this post.
Hope that helps!

Unable to process a file using grunt copy-task

I'm trying to use grunt-contrib-copy (version 0.4.1) to rewrite some strings inside a file during the build process. As a test I can copy the file, so it's not a permissions or location problem.
These are the options for the fileProcessor task (in Coffeescript syntax) to copy the file:
fileProcessor:
files: [
expand: true
cwd: "target/js/"
dest: "target/js/"
src: ["**/test-*.js"]
rename: (dest, src) ->
grunt.verbose.writeln src, " => ", dest + src.substring(0, src.lastIndexOf("/") + 1) + "foo.js"
dest + src.substring(0, src.lastIndexOf("/") + 1) + "foo.js"
]
I get the following output, everything worked as expected:
Running "copy:fileProcessor" (copy) task
Verifying property copy.fileProcessor exists in config...OK
test-25fd6a1c3a890933.js => target/js/foo.js
Files: target/js/test-25fd6a1c3a890933.js -> target/js/foo.js
Options: processContent=false, processContentExclude=[]
Options: processContent=false, processContentExclude=[]
Copying target/js/test-25fd6a1c3a890933.js -> target/js/foo.js
Reading target/js/test-25fd6a1c3a890933.js...OK
Writing target/js/foo.js...OK
Copied 1 files
So far so good. Clearly grunt-contrib-copy has no problem with the file itself. So I replace the the rename task with a process task, and use a simple regex to see if it works:
fileProcessor:
files: [
expand: true
cwd: "target/js/"
dest: "target/js/"
src: ["**/test-*.js"]
processContent: (content, src) ->
re = new RegExp("(angular)+")
content.replace(re, "foo")
]
Which produces the following output:
Running "copy:fileProcessor" (copy) task
Verifying property copy.fileProcessor exists in config...OK
Files: target/working/shared/scripts/bootstrap-25fd6a1c3a890933.js -> target/working/shared/scripts/bootstrap-25fd6a1c3a890933.js
Options: processContent=false, processContentExclude=[]
Options: processContent=false, processContentExclude=[]
Copying target/working/shared/scripts/bootstrap-25fd6a1c3a890933.js -> target/working/shared/scripts/bootstrap-25fd6a1c3a890933.js
Reading target/working/shared/scripts/bootstrap-25fd6a1c3a890933.js...OK
Writing target/working/shared/scripts/bootstrap-25fd6a1c3a890933.js...OK
Copied 1 files
So grunt-contrib-copy finds the file I need to process, but the processing never happens. processContent remains set to the default false.
Looking in copy.js, when grunt.file.copy(src, dest, copyOptions) is called, copyOptions is an object with only two properties:
process, which is false, and
noProcess, which is an empty array.
So my process options are never passed along. Any ideas on why this could be?
your processContent is in the wrong place, it needs to be wrapped into options and moved one level higher. Also note that processContent is depreciated and replaced by process
fileProcessor:
files: [
expand: true
cwd: "target/js/"
dest: "target/js/"
src: ["**/test-*.js"]
]
options:
process: (content, src) ->
re = new RegExp("(angular)+")
content.replace(re, "foo")

grunt-contrib-copy error (Error code: ENOENT)

I searched internet and it looks only me had this problem with grunt-contrib-copy.
project
gruntfile.js
->app
->img
->pic1.png
->pic2.png
Result I expected:
project
gruntfile.js
->app
->dist
->img
->pic1.png
->pic2.png
->img
->pic1.png
->pic2.png
In another word, just copy files in /project/app/img to /project/app/dist/img.
Here is my copy config, which is NOT working:
copy: {
main: {
src: ['*.*'],
expend: true,
cwd: 'app/img/',
dest: 'app/dist/img/'
}
},
Here is error message:
Warning: Unable to read "download.png" file (Error code: ENOENT). Use --force to continue.
(download.png is the name of picture file)
How should I config the copy option? Thank you!
It looks like you have a typo, it should be expand instead of expend. So the cwd property is being ignored. Try the following config instead:
copy: {
main: {
src: ['**/*'],
expand: true,
cwd: 'app/img/',
dest: 'app/dist/img/'
}
},
The glob pattern *.* is probably not necessary as * will already match all files (unless you're specifically trying to match only files with a . in them.) Try using src: '*' to match all files within the single folder or src: '**/*' to match all files and folders within the cwd.

Grunt rename not working

My directory structure looks like this:
-src/
-----pages/
----------...
-----...
-build
My gruntfile contains the following task:
copy: {
all:{
dest:"<%= builddir %>/",
src: ["src/**/*.{yaml,yml,py,html,htm,json,css}"],
rename:function(d, s){return d.replace("src/","");}
}
},
builddir: "build/<%= pkg.name %>-<%= pkg.version %>-<%= date %>",
When I run the copy task, it copies all the selected files into the directory containing the package name, version and build date, as expected, but it copies the entire src directory. while I only want to copy the contents of the src directory, so I'm trying to remove src/' from dest using therename`property, which doesn't work for some reason.
I've only started using grunt today, so I might be makiing a rookie mistake here.
Hmm... I think all you need is the cwd (current working directory) option. Unless you in fact want to flatten the files into a single directory.
copy: {
all:{
expand: true,
dest:"<%= builddir %>/",
src: ["**/*.{yaml,yml,py,html,htm,json,css}"],
cwd: "src/"
}
}
You'll need to set the flatten option, which removes the directory structure.
copy: {
all:{
expand: true,
flatten: true,
dest:"<%= builddir %>/",
src: ["src/**/*.{yaml,yml,py,html,htm,json,css}"]
}
}

Resources