Here's one property from a gruntfile I'm reviewing:
'uglify': {
'build': {
'files': {
'<%= config.files.js_app_min %>': '<%= config.files.js_app_min %>'
}
}
},
Would 'uglify' represent a grunt task in this scenario? Does the subobject under the top level object simply represent a task-specific configuration object?
The task name base on developer.
read Creating plugins and Creating tasks.
For example grunt-contrib-copy is a simple plugin. Let's see its code.
the config of a plugin in grunt.initConfig is base on this code:
grunt.registerMultiTask('copy', 'Copy files.', function() {.
The task name which developer register like copy will be the configObject in grunt.initConfig.
In effect, the task name can named whatever you want. It's more like a conventional way we develop a plugin
Related
While configuring my task I want to use current file name the task works on as a template variable in task options object. For example in options['wrap-start'] here:
swig_compile: {
temptarget: {
options: {
'wrap-start': 'var <%= CURRENT.FILE.NAME %> = function {', //I want the current file name as function name here
'wrap-end': '};'
},
files: {
'<%= config.app %>/scripts/tempcompiled.js': ['<%= config.app %>/templates/*.swig']
}
}
}
According to grunt-swig-compile sources, there is no such feature. options['wrap-start'] is concatenated to the result as is.
You can fork/copy the grunt-swig-compile sources and simply add a replacement of your pattern (e.g. <%= file_name %>) with the path.basename(filepath) in options['wrap-start'].
I need to inject custom CSS files everytime they are created after being compiled by gulp-less. So I tried to use wiredep with custom configurations, but without success.
I changed the tag from 'bower:css' to 'custom:css', specifically to my custom task. The bower:css for default wiredep injection is still there. But after run myinjection task nothing is injected even running the task without errors.
Another weird thing, when I run my task, the files injected by wiredep (the default) disappear.
What I'm missing?
Basicaly my files structure is like this:
|---app
|---styles
|---***
*.css
*.html
.custom.json
I'm not sure if I really need a file similar to bower.json, but I made may own custom.json
{
"name": "custom",
"version": "0.0.1",
"main": [
"app/styles/**/*.css",
"app/scripts/**/*.js //pretend to inject custom js later
]
}
The task in gulpfile.js is like this:
gulp.task('myinject', function () {
var myinject = require('wiredep').stream;
var combined = Combine (
gulp.src('app/*.html'),
myinject({
directory: 'app',
bowerJson: require('./custom.json'),
dependencies: false,
html:
{
block: /(([ \t]*)<!--\s*custom:*(\S*)\s*-->)(\n|\r|.)*?(<!--\s*endcustom\s*-->)/gi,
detect: {
js: /<script.*src=['"](.+)['"]>/gi,
css: /<link.*href=['"](.+)['"]/gi
},
replace: {
js: '<script src="{{filePath}}"></script>',
css: '<link rel="stylesheet" href="{{filePath}}" />'
}
}
}),
gulp.dest('app')
);
combined.on('error', function(err) {
console.warn(err.message);
});
return combined;
});
Thanks in advance
I had a similar issue that I resolved with gulp-inject rather than wiredep.
Wiredep works fine with me when I need to include a third-party dependency (e.g. a bower package with a valid main file declared in the bower.json or a file with the same name as the directory).
However, when you want to include only a specific file (e.g. only the main.css of html5-boilerplate) gulp-inject is much simpler. Here is an extract of the doc :
gulp.task('index', function () {
var target = gulp.src('./src/index.html');
var sources = gulp.src(['./src/**/*.js', './src/**/*.css'], {read: false});
return target.pipe(inject(sources))
.pipe(gulp.dest('./src'));
});
Can I instruct Grunt to concatenate all JS files defined in
index.html without specifically naming them?
Can Grunt also create new index.html file that will load the concatenated JS file instead
of the previous multiple files?
Can Grunt also uglify the JS file at a same time?
Can Grunt do this not only for JS files but also CSS files used in a given html file?
I spent significant time googling but the Grunt ecosystem seems to be so fragmented and so unfamiliar to me :(.
PS: I have decided to use Grunt because there is direct integration in WebStorm 8 but maybe other tool would be more suitable for this task?
There are many different solutions available which is why it seems fragmented. I'll describe a couple of the seemingly popular methods.
Use grunt-usemin
You specify blocks within your HTML that it reads and feeds to your other Grunt tasks (concat, uglify, etc). Their docs have extensive examples to handle a lot of different scenarios.
Use a module bundler such as grunt-webpack, grunt-browserify or grunt-contrib-requirejs
Instead of adding script tags to your HTML, use a require() syntax to include files when needed. Which, depending on the method, will add the scripts to your page or bundle into a single file. These methods only require including, usually, a single javascript file.
Explore and figure out which solution makes the most sense for your needs.
I solved this problem by adding this function at the top of my Gruntfile:
var isCssRegex = /^\s*<\s*link.*href=["']([^"']*)["'].*$/i;
var isJsRegex = /^\s*<\s*script.*src=["']([^"']*)["'].*$/i;
var extractJsRegex = /src\s*=\s*"(.+?)"/
var extractCssRegex = /href\s*=\s*"(.+?)"/
function extractFilenames(src, type) {
var filenames = [];
var data = require('fs').readFileSync(src, 'utf8');
var lines = data.replace(/\r\n/g, '\n').split(/\n/);
var webContent = require('path').dirname(src);
lines.forEach(function (line) {
if (line.match(type === 'css' ? isCssRegex : isJsRegex)) {
var src = line.match(type === 'css' ? extractCssRegex : extractJsRegex)[1];
filenames.push(webContent + '/' + src);
}
});
return filenames;
};
Then in my concat task, I can do this:
concat: {
js: {
src: extractFilenames('src/main/resources/public/index.html', 'js'),
dest: 'build/app.js'
},
css: {
src: extractFilenames('src/main/resources/public/index.html', 'css'),
dest: 'build/style.css'
}
},
I'm using Grunt to concat and minify files (with grunt-contrib-uglify and grunt-contrib-concat ) and I wanted to add a source map. The uglify docs say to just add an option for sourceMap set to a boolean of true. But when I add that to my tasks (I've tried a couple different ones) the process runs fine until it gets to the source map part, then I get:
Writing true...ERROR
Warning: Unable to write "true" file (Error code: undefined). Use --force to continue.
The concatenation is done, the minification is done. But... no luck with the sourcemap.
Sample from my Grunt file:
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= pkg.version %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
},
publicjs: {
options: {
sourceMap: true
},
files: {
'js/<%= pkg.name %>_public.min.js': ['<%= concat.publicjs.dest %>']
}
}
}
(I've also tried with the sourceMap in my top level options object.)
Any ideas? Clearly Grunt can write to the directory because it creates the concatenated and minified files, and I can't think of what else might be the trouble.
https://github.com/gruntjs/grunt-contrib-uglify
Section " Migrating from 2.x to 3.x" mentions this:
sourceMap - Only accepts a Boolean value. Generates a map with a
default name for you
So it looks like you are using an older version with the new version's config options.
You can upgrade.
Or use the older version's config options. (I think you should assign the destination file name to this variable instead of true. But I didn't verify in the old version's documentation.)
I have a task in Grunt for clean, and I have another task for copy. Basically, I clean out some stuff in one place, and then replace it with new stuff, going into the same places. I can't figure out how to map my copy.files.dest such that it uses the values from clean.env.files.src, but switches the modifier. So:
// Project settings
yeoman: {
// configurable paths
app: 'app',
dist: 'dist',
prod:'L:/dist'
}
// the prod sub-block of the clean task configuration
prod:{
files:[{
dot:true,
src:[
'<%= yeoman.prod% >/scripts',
'<%= yeoman.prod% >/styles',
'<%= yeoman.prod% >/views',
'<%= yeoman.prod% >/*.html',
'<%= yeoman.prod% >/images'
]
}]
}
//the prod sub-block of the copy task configuration
prod:{
files:[{
expand:true,
dot:true,
cwd:'<%= yeoman.dist %>',
dest:'<%= yeoman.prod %>',
//can i use the result files from this path, but use yeoman.dist instead of yeoman.prod?
src:['<%= clean:prod:files:src %>']
}]
}
I want to use the template from <%= clean:prod:files:src %> but use an alternate configuration (in other words, that task uses yeoman.prod, whereas I want all the same files listed, and to do some would need to src from yeoman.dist instead).
Is there a way to do this via grunt syntax, or do I have to rely on my (not shown) custom function instead?
Edit, removed references to parent task, since they do not reflect what my code actually looks like.
Always remember, Gruntfiles are javascript. They must be written in valid javascript.
clean.prod:{} isn't valid javascript.
The dot notation used in Grunt templates, <%= clean.prod %> is merely a template format to translate through javascript objects but not part of the javascript language itself.
So instead change your config to:
clean: {
prod: {
src: [ /* file patterns here */ ]
}
}
and then access the src property of the clean:prod task with: <%= clean.prod.src %>.
I've taken the config out of the files array, as if you only have a single src/dest block within your target, prod, it is not needed. But if you wanted to access values from that location in the config, you have to remember files is an array. So accessing the first item of the array with the template would be: <%= clean.prod.files[0].src %>. But it is much simpler to just not use the files array unless needed.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects for more info about javascript objects and http://gruntjs.com/configuring-tasks#templates for more info about grunt templates.