Create two configurations for a grunt plug-in that is not multi-taskable - gruntjs

I use a grunt package called grunt-preprocess, Obviously, it doesn't support multi-tasks.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
preprocess: {
options: {
context: {
ENV: grunt.option('env') || 'prod'
},
},
all_from_dir: {
src: '*.*',
cwd: 'src/',
dest: 'src',
expand: true
}
},
})
Now I want to execute preprocess twice, once from the src directory, and once from the dist directory. How should I configure this package to achieve that?
I have tried this configuration;
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
preprocess: {
first: {
options: {
context: {
ENV: grunt.option('env') || 'prod'
},
},
all_from_dir: {
src: '*.*',
cwd: 'src/',
dest: 'src',
expand: true
}
},
second: {
options: {
context: {
ENV: grunt.option('env') || 'prod'
},
},
all_from_dir: {
src: '*.*',
cwd: 'dist/',
dest: 'dist',
expand: true
}
}
}
})
and then execute grunt preprocess:first. However it does not work:
PS D:\workspace\environment-compile> grunt preprocess:first
Running "preprocess:first" (preprocess) task
Done.

Yes, you're right preprocess is single Task only, therefore doesn't allow multiple targets to be defined.
You'll need to create another custom task that dynamically configures the preprocess Task and then runs it.
For example:
Gruntfile.js
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-preprocess');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
preprocess: {
options: {
context: {
ENV: grunt.option('env') || 'prod'
},
},
all_from_dir: {
src: '*.*',
cwd: 'src/',
dest: 'src',
expand: true
}
},
// ...
});
// Custom task dynamically configures the `preprocess` Task and runs it.
grunt.registerTask('preprocess_dist', function() {
grunt.config.set('preprocess.all_from_dir.cwd', 'dist/');
grunt.config.set('preprocess.all_from_dir.dest', 'dist');
grunt.task.run(['preprocess']);
});
grunt.registerTask('preprocessBoth', [ 'preprocess', 'preprocess_dist' ]);
};
Running:
Via your CLI run the following single command to execute the preprocess task twice, once from the src directory, once from the dist directory:
grunt preprocessBoth
Explanation:
The custom Task named preprocess_dist dynamically configures the values for the cwd and dest properties, setting them to 'dist/' and 'dist' respectively. This is done via the grunt.config.set method
Then the task is run via the grunt.task.run method.
The last line of code that reads:
grunt.registerTask('preprocessBoth', [ 'preprocess', 'preprocess_dist' ]);
creates a task named preprocessBoth and adds the following two tasks to to the taskList:
preprocess
preprocess_dist
Essentially what happens when you run grunt preprocessBoth is:
The preprocess task runs using files from the src directory.
Then the custom preprocess_dist task runs using files from the dist directory.
If you prefer, you can also run each task independently via CLI, i.e:
grunt preprocess
and
grunt preprocess_dist

Related

Create matching file names in Grunt

I've got several projects that each use an identical Gruntfile to run tasks and put the output in their own dist folder. Folder setup:
MyProjects
- Project1
- src
- dist
- Project2
- src
- dist
.....
I can't figure out how to run Grunt at the top level (MyProjects) and still have the output generated in the correct dist folder dynamically.
Is there a way I can have Grunt put the output in the correct dist folder without having to hard code it into the Gruntfile? Something like:
dist: {
files: {
// destination : source js
'<% ProjectName %>/dist/app.js': '<% ProjectName %>/src/app.js'
},
Thanks
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
// Project configuration.
grunt.initConfig({
watch: {
scripts: {
files: ['src/**/*.js'],
tasks: ['browserify', 'file_append', 'concat'],
options: {
spawn: false
}
},
sass: {
files: "src/scss/*.scss",
tasks: ['sass', 'file_append', 'concat']
}
},
sass: {
dist: {
options: {
style: 'expanded'
},
files: {
// destination // source file
"format/css/styles.css": "src/scss/styles.scss"
}
},
options: {
sourcemap: "none",
style: "compact",
noCache: true
}
},
file_append: {
default_options: {
files: [
// Development build
{
append: "",
prepend: "",
input: "format/app.js",
output: "format/dev.app.js"
},
{
append: "</style>`)",
prepend: "document.body.insertAdjacentHTML('afterbegin', `\n<style>\n",
input: "format/css/styles.css",
output: "format/css/dev.styles.html"
},
// Production build
{
append: "</script>",
prepend: "<script>\n",
input: "format/app.js",
output: "format/prod.app.html"
},
{
append: "</style>",
prepend: "<style>\n",
input: "format/css/styles.css",
output: "format/css/prod.styles.html"
}
]
}
},
concat: {
options: {
seperator: '\n'
},
// Development build
dev: {
src: ['format/dev.app.js', 'format/css/dev.styles.html'],
dest: 'dev/dev.app.js'
},
// Production build
prod: {
src: ['format/prod.app.html', 'format/css/prod.styles.html'],
dest: 'dist/prod.app.html'
}
},
browserify: {
dist: {
files: {
// destination for transpiled js : source js
'format/app.js': 'src/app.js'
},
options: {
transform: [
[
'babelify', {
presets: "es2015",
comments: false,
plugins: "transform-object-rest-spread"
}
]
],
browserifyOptions: {
debug: false
}
}
}
}
});
grunt.registerTask('default', [
'sass',
'browserify:dist',
'file_append',
'concat',
'watch'
]);
};
There's a couple ways you can tackle this.
One option is to overload the arguments you pass to the task & include the folder name you wish to target.
grunt sass:dist:Project1
The additional argument is accessible via lodash templates which are a part of the GruntJS framework, and allows the configuration to be set at the time the task is ran:
sass: {
dist: {
options: {
style: 'expanded'
},
files: {
// destination // source file
"MyProjects/<%= grunt.task.current.args[0] %>/format/css/styles.css": "MyProjects/<%= grunt.task.current.args[0] %>/src/scss/styles.scss"
}
},
options: {
sourcemap: "none",
style: "compact",
noCache: true
}
}
This approach works in the context of the function that's executing, but it wouldn't continue to pass the args to the next task. To do that, we need to add a custom task which will set a configuration object before executing the task list:
grunt.registerTask("build", (project) => {
const buildConfig = { project };
grunt.config.set("build", buildConfig);
grunt.task.run([
'sass',
'browserify:dist',
'file_append',
'concat',
'watch'
]);
});
Now when we run grunt build:Project1, your custom task build will run and set the property we passed in the grunt config object. We can then reference that value in our other grunt config objects using lodash like we did for the first option. To access config values with lodash templates, we just have to provide the config pointer in json notation:
files: {
"MyProjects/<%= build.project %>/format/css/styles.css": "MyProjects/<%= build.project %>/src/scss/styles.scss"
}
Grunt compiles the configs required for a task at the time they're run & will process the lodash templates then, allowing you to inject your project name into a task. Since we stored the value in the config object, the value will persist through until grunt completes and exits.

Running minified in Grunt cannot read property of undefined

I'm trying to build a Grunt task that minifys my JS files and return a single minified JS file.
This is my gruntfile.js file:
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
minified: {
files: {
src: [
'js/*.js',
],
dest: 'js/min/'
},
options: {
allinone: true
}
},
});
grunt.loadNpmTasks('grunt-minified');
};
When I run the task it does work, but it also returns an error.
> cmd.exe /c grunt -b "C:\Users\alucardu\documents\visual studio 2015\Projects\JS-demo\JS-demo" --gruntfile "C:\Users\alucardu\documents\visual studio 2015\Projects\JS-demo\JS-demo\Gruntfile.js" minified
Running "minified:files" (minified) task
Warning: Cannot read property 'yellow' of undefined Use --force to continue.
Process terminated with code 3.
Aborted due to warnings.
I've done a search action in my entire solution for 'yellow' but it doesn't return any results. Also when I empty both my JS files that are being minified it still returns the error.
Does anyone know why it's returning this error?
By removing the
options: {
allinone: true
}
The warning no longer showed up, but it also doesn't concat the files together. So I've added another task called concat. So now my gruntfile looks like this:
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
watch: {
scripts: {
files: ['js/*.js'],
tasks: ['concat', 'minified', 'uglify'],
},
},
concat: {
dist: {
src: ['js/*.js'],
dest: 'js/min/concat.js'
},
},
minified: {
files: {
src: ['js/min/concat.js'],
dest: 'js/min/minified.js'
},
},
uglify: {
my_target: {
files: {
'js/min/uglify.js': ['js/min/minified.jsconcat.js']
}
}
},
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-minified');
grunt.loadNpmTasks('grunt-contrib-uglify');
};
And it seems to be working fine.

task jade not found when running grunt

When I run grunt with the following Gruntfile, I get the error Warning: task "jade" not found. what exactly could be wrong here?
module.exports = function(grunt) {
grunt.initConfig({
jade: {
compile: {
options: {
client: false,
pretty: true
},
files: [ {
cwd: "app/views",
src: "**/*.jade",
dest: "build/templates",
expand: true,
ext: ".html"
} ]
}
}
});
grunt.registerTask('default','Convert Jade templates into html templates',
['jade','watch']);
grunt.loadNpmTasks('grunt-contrib-watch');
};
You need to load grunt jade task. The same as yo are adding grunt-contrib-watch
grunt.loadNpmTasks('grunt-contrib-jade');
This should works.

Specify one normal task and one watching task with Grunt Browserify

I use Watchify (via grunt-browserify) for fast compilation during local dev:
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: {
app: {
src: './src/app.js',
dest: 'build/js/app.js'
},
options: {
// next two lines for watchify + watch instead of browserify
watch: true,
keepAlive: true,
transform: ['node-lessify', 'node-underscorify'],
debug: true,
browserifyOptions: {
debug:true // include source maps. currently only available with browserify
}
}
}
}
grunt.loadNpmTasks('grunt-browserify');
Running grunt browserify enters a while true loop that continuously watches for changes. When it comes to build a production-ready bundle, I want it to run through once and not watch.
I have tried this configuration but the browserify:dev task never watches:
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: {
dev: {
src: './src/app.js',
dest: 'build/js/app.js',
// next two lines for watchify + watch instead of browserify
watch: true,
keepAlive: true
},
package: {
src: './src/app.js',
dest: 'build/js/app.js'
},
options: {
transform: ['node-lessify', 'node-underscorify'],
browserifyOptions: {
debug:true // include source maps. currently only available with browserify
}
}
}
});
How can I specify one Browserify task that watches with Watchify, and one task that builds the whole package and exits?
I had my configuration wrong. Note that keepAlive: false is in the options namespace of the browserify:package job:
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: {
dev: {
src: './src/app.js',
dest: 'build/js/app.js'
},
package: {
src: './src/app.js',
dest: 'build/js/app.js',
options: {
keepAlive: false
}
},
options: {
watch: true,
keepAlive: true,
transform: ['node-lessify', 'node-underscorify'],
browserifyOptions: {
debug:true // include source maps. currently only available with browserify
}
}
}
});

Grunt task arguments do not work

I'm trying to configure grunt to have 2 tasks (development and production). But for whatever reason, whenever I add an argument, the task gets run (as you will see) but there is not output/action:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
dev: {
options: {
// define a string to put between each file in the concatenated output
separator: ';'
},
dist: {
// the files to concatenate
src: [
'public/js/jquery-1.10.2.min.js'
],
// the location of the resulting JS file
dest: 'public/js/aaaaa.src.js'
}
},
prod: {
options: {
// define a string to put between each file in the concatenated output
separator: ';'
},
dist: {
// the files to concatenate
src: [
'public/js/jquery-1.10.2.min.js'
],
// the location of the resulting JS file
dest: 'public/js/bbbbbb.src.js'
}
}
}
});
// Load Plugins
grunt.loadNpmTasks('grunt-contrib-concat');
// Default task(s).
grunt.registerTask('default', ['concat:dev']);
});
Output:
$ grunt
Running "concat:dev" (concat) task
Done, without errors.
The plugin does not support nested targets:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
dev: {
// the files to concatenate
src: [
'public/js/jquery-1.10.2.min.js'
],
// the location of the resulting JS file
dest: 'public/js/aaaaa.src.js'
},
prod: {
// the files to concatenate
src: [
'public/js/jquery-1.10.2.min.js'
],
// the location of the resulting JS file
dest: 'public/js/bbbbbb.src.js'
}
}
});
// Load Plugins
grunt.loadNpmTasks('grunt-contrib-concat');
// Default task(s).
grunt.registerTask('default', ['concat:dev']);
});

Resources