How can I run concat for cases without any scripts? - javascript

As a part of my Gruntfile.js:
...
concat: {
...
js: {
src: [
'src/**/*.js'
],
dest: 'build/js/main.js',
nonull: true
}
},
...
How can I prevent concat from generating a blank main.js if my src directory contains no scripts? Must I really create a separate task if I know I won't need to build any scripts?

Not exactly a proper solution, but I managed to find a package called grunt-cleanempty which I set to run after concat to delete any generated empty files.

Related

Grunt build script that reads xml file to determine which files are copied

copy: {
build: {
cwd: 'app',
src: ['**', '!**/vendors/**', '!**src/js/*.js',],
dest: 'dist',
expand: true
}
}
I am using grunt build scripts to build a distribution folder for the completed product. However, its not 100% automatic and dynamic. For example, I have a folder of xml content files. Yet, I don't use them all. Right now, the whole folder is copied over to the build version. Manually I have to go in and delete the xml files I don't want in the build version then run it. Or I could go into the grunt file and and tell it to ignore those files.
The problem is that I don't want to do that every time. A theoretical idea I had would be to have an xml file where I define elements to represent certain other files.
<bootstrap>true</bootstrap>
<extraContent>false</extraContent>
This would say that the file correlated to bootstrap and extraContent should or shouldn't be ignored in the build. I am trying to figure out if you could do this in grunt.
something like the following is how I see the logic playing out...
var bootstrap = $(xml).find("bootstrap").text()
if(bootstrap == "false"){
var url = src/bootstrap.css
//Here add the correlated filepath defined above to be ignored
}
The problem is not only writing this so grunt knows what it is, but also combining that logic with the actual "copy:{}" script I showed above
If you want to include/exclude files based on their contents you can use filter function for this. Examples can be found in the official documentation: https://gruntjs.com/configuring-tasks#custom-filter-function.
The filter property can help you target files with a greater level of detail.
In your case this could be something like this:
copy: {
build: {
cwd: 'app',
src: ['**', '!**/vendors/**', '!**src/js/*.js',],
dest: 'dist',
expand: true,
// this filter function will copy xml files only when `bootstrap` is set to 'true'
filter: filepath => {
if (require('path').extname(filepath) !== 'xml')
return true;
const xml = require('fs').readFileSync(filepath, 'utf8');
const json = require('xml2json').toJson(xml);
return json.bootstrap === 'true';
}
}
}
You can then use the process function to copy only certain contents from specific files: https://github.com/gruntjs/grunt-contrib-copy#process
This option is passed to grunt.file.copy as an advanced way to control the file contents that are copied.

Grunt read .json file to concat list of html files

I’m trying to get grunt to concat some .css files from 2 different directories into a single css file
I got it working ok and am trying to write a similar piece of code to concat html files in the order I specify in a simple external .json file rather than editing the Grunfile.js directly each time but it keeps throwing errors
The file locations and permissions are all ok, I can do it with php or concat the css files ok, I’m not great on js syntax os using functions. I only learned to use Grunt in the last few days so am pretty sure have not called the file with the correct code??
Any advice kindly appreciated!
This is my Gruntfile.js exactly
module.exports = function(grunt) {
// 1. All configuration goes here
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
// 2. Configuration for concatinating files goes here
file.readJSON(‘html-files.json’);
},
watch: {
files: ['../../pages/**/*.html’],
tasks: ['concat'],
options : { nospawn : true }
}
});
// 3. Where we tell Grunt we plan to use this plug-in
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
// 4. Where we tell Grunt what to do when we type "grunt" into the terminal.
grunt.registerTask('default', ['concat']);
};
This is the html-files.json file contents exactly
html: {
src: [
'../../pages/**/this-block.html',
'../../pages/**/that-block.html',
],
dest: '../../somepage/content.html',
}

How to concatenate groups of scripts separately in Grunt?

I was looking into the possibility of building a webapp that conditionally loads groups of scripts based on the screen size and/or client of the user, because there may be some UX or client specific code that I might load based on this information.
I saw another question that showed how to have files minified separately (see link), but I wasn't sure if there was an option to take all scripts in group A, B, and C and minify them separately to groupA.min.js, groupB.min.js, and groupC.min.js. Is this possible?
Thanks,
- Daniel
Example:
uglify: {
dist: {
files: {
'dist/shared.min.js': 'src/shared/*', //would recurse shared directory and concatenate/minify all JS in subdirectories
'dist/desktop.min.js': 'src/platform/desktop/*',
'dist/mobile.min.js': 'src/platform/mobile/*',
'dist/ios.min.js': 'src/platform/ios/*',
'dist/android.min.js': 'src/platform/android/*'
}
}
}
Something along these lines should work according to the docs, which I've partly butchered:
grunt.initConfig({
concat: {
groupA: {
// concat task "groupA" target options and files go here.
dist: {
// the files to concatenate
src: ['src/groupA/*.js'],
// the location of the resulting JS file
dest: 'dist/groupA.concat.js'
}
},
groupB: {
// concat task "groupB" target options and files go here.
},
},
uglify: {
groupA: {
// uglify task "groupA" target options and files go here.
},
groupB: {
// uglify task "groupB" target options and files go here.
},
},
});
Then you can run specific task with grunt concat:groupA or grunt concat:groupB.

Concat specified js files and copy all the other js files to output dir

I want to concat a couple of js files I have in my src/ directory, like the ones that are needed on every page and for some specific pages that need multiple files.
The rest of the files I want to copy with the current directory structure in tact. These are the files that are used only on one page and are the only page specific jsfile for that page.
So I would like to exclude the src and files attributes of the first type of tasks and exclude those in the last task.
How can this be achieved?
You could use create an array with all the files you mean to concatenate outside task scope. Then you loop through that array to concatenate the javascript files listed in the array in one task like uglify and create another task to copy all the files through another task like copy.
But the magic would happen when you use the same pre-defined array to list the exceptions that are not going to be included in the copy task.
OR you could prefixes like:
uglify: {
dist: {
files: {
'dest/output.min.js': [
'app/js/**/concatenate-*.js',
]
}
}
}
copy: {
dist: {
src : [
'app/js/**/*.js',
// exclude files
'!app/js/**/concatenate-*.js'
]
}
}
Note that I only added the relevant part within each task, normally the tasks would need more configuration than just that.

How to watch and process (the same way) several files into several outputs with Grunt and/or Gulp?

I am currently using Grunt, and as I was trying Gulp, the same problem I encountered first with Grunt occurred to me.
I am trying to process some js files (concat, uglify and minify them), but I don't want all of them to compile into one big file, I want multiple output files, each from the processing of some input files :
scripts =
firstOutput:
outputFilename: 'first.min.js',
inputFiles: ['one.js', 'two.js']
secondOutput:
outputFilename: 'second.min.js',
inputFiles: ['three.js']
thirdOutput:
outputFilename: 'third.min.js',
inputFiles: ['four.js', 'five.js']
The only way I found (for now) to achieve that with Grunt is with multiple watches and multiple uglify tasks (or one uglify task and a listener on watch change to dynamically modify the uglify task src and dest) :
module.exports = (grunt) ->
grunt.loadNpmTasks 'grunt-contrib-watch'
grunt.loadNpmTasks 'grunt-contrib-uglify'
grunt.initConfig
watch:
firstOutput:
files: scripts.firstOutput.inputFiles
tasks: ['uglify:firstOutput']
options :
spawn : false
secondOutput:
files: scripts.secondOutput.inputFiles
tasks: ['uglify:secondOutput']
options :
spawn : false
thirdOutput:
files: scripts.thirdOutput.inputFiles
tasks: ['uglify:thirdOutput']
options :
spawn : false
uglify:
firstOutput:
files: scripts.firstOutput.inputFiles
dest: scripts.firstOutput.outputFilename
secondOutput:
files: scripts.secondOutput.inputFiles
dest: scripts.secondOutput.outputFilename
thirdOutput:
files: scripts.thirdOutput.inputFiles
dest: scripts.thirdOutput.outputFilename
grunt.registerTask 'default', 'watch'
And, as you can imagine, this is just an example, in my case of a big web application, there's a lot more than just three output js files, and I also process a few less files into some css files
My Gruntfile is really huge, and I find it has a lot of duplicate code, is there any way to have this code refactored to have one watch and one uglify task, with an automatically guessed src and dest with some kind of dependency (to know that if the four.js file is modified, it has to process the third output) ?
If you have some way to do it with Gulp I'll take it with great pleasure, as I would like to test it in my usual workflow.
Here's how you can do this with gulp + vanilla javascript:
var _ = require("underscore")
, gulp = require("gulp")
, uglify = require("gulp-uglify")
var scripts = [
{
output: 'first.min.js',
input: ['one.js', 'two.js']
}
, {
output: 'second.min.js',
input: ['three.js']
}
, {
output: 'third.min.js',
input: ['four.js', 'five.js']
}
];
function build(files, dest) {
return gulp.src(files)
.pipe(uglify())
.pipe(gulp.dest(dest));
}
gulp.task("watch", function () {
_.each(scripts, function (script, i) {
gulp.watch(script.input, function () {
build(script.input, script.output);
});
});
});
Even better if you can use globs to match sets of files so you don't have to write out the path for every single input set. Something like input: ["one/**/*.js, "other/**/*.js"]
"I am trying to process some js files (concat, uglify and minify
them), but I don't want all of them to compile into one big file"
Can I ask why? The benefit of one larger file is that you save on HTTP requests, every resource you load will cause some slowdown of your website. May I suggest using proper dependency management with RequireJS? That way the optimiser can walk your dependency graph and output optimised files for you.
http://requirejs.org/
There's a grunt task for this too:
https://github.com/gruntjs/grunt-contrib-requirejs

Categories