Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for adding additional grunt tasks to 'yeoman build' et al #491

Closed
christopherscott opened this issue Sep 17, 2012 · 29 comments
Closed
Assignees
Milestone

Comments

@christopherscott
Copy link

I'd like to add additional grunt tasks to a Yeoman project, but I'm not sure how to add these to the existing yeoman build command (apart from editing the source). Is this configurable?

@addyosmani
Copy link
Member

Build targets can be extended (including the default Yeoman one) using cli/yeoman.js. At the moment we don't allow these to be otherwise configured elsewhere. Hope that helps!

@pajtai
Copy link

pajtai commented Sep 19, 2012

Below is a possible solution if you only want to modify Gruntfile.js and want to leave yeoman.js alone.

This is definitely the WRONG WAY to do it, but you can splice in custom tasks with aliasing and renaming. I'm sure there is a much better way, but I'm new to Grunt / Yeoman.

For example to get a custom task something to run. You can repurpose an existing task used by Yeoman. For example I wanted to run a synch task right before copy (I needed to do a bunch of file cleanup... deleting unused files, etc.).

Of course this only lets you build on top of existing build targets, but you can do quite a bit like this, especially if there is a build target you don't generally use that has a task you don't often use.... like I said this is the wrong way to do this! (or if there is a task you want to splice in that will always run, like the case below)

// You can put the code below directly in the Gruntfile.js module
// For example right after the existing grunt.registerTask 
grunt.renameTask('copy', 'oldCopy');

// Register the task you want run. Task or multiTask
grunt.registerMultiTask('something', 'This does something', function() { ... });

// Run both the original and the custom on the grunt.initConfig() in Gruntfile.js
grunt.registerTask('copy', 'something oldCopy');

@christopherscott
Copy link
Author

@pajtai good suggestion; i wasn't aware of renameTask. That might be exactly what I need. I basically needed to run a task that would compile my templates and then run the build task. I guess this only works if you want to prepend or append a task, right now there's no way to insert them.

Ideally Yeoman would expose configuration to override the default targets in the Gruntfile.js something like this:

override_targets: {
    default: 'mytask rjs concat css min img myothertask rev usemin manifest',
}

I'm not sure if something similar is already being considered by the core devs, but I feel like this should be an enhancement request.

This also might help with swapping out certain tasks for others (like swapping out rjs for requirejs, see issue #440)

@pajtai
Copy link

pajtai commented Sep 20, 2012

@christopherscott

And it looks like you can just plain clobber the targets object and fully customize it in Gruntfile.js.

The only caveat is that you also have to override targetList and the build task since it they make immediate use of targets

This method seems cleaner then the previous, and it still lets you leave the yeoman core unmodified (of course you'll have to keep an eye on targetList, targets, and build and modify accordingly if they change, but you don't have to muck around in the /usr/local/lib/node_modules/yeoman directory, or wherever yours is.

seems to work.

/***************************************************************

  Put the following in Gruntfile.js
  It allows you to create a full custom set of build targets.

*/
    'use strict';

    // Clobber the original targets
    var targets = {
        // Add as many custom targets as you want, using custom modules, etc.
        custom: 'concat css min usemin other this that blah',      

        // Keep the existing targets
        default   : '               rjs concat css min img rev usemin manifest',
        usemin    : 'usemin-handler rjs concat css img rev usemin manifest',
        text      : 'usemin-handler rjs concat css min     rev usemin manifest',
        buildkit  : 'usemin-handler rjs concat css min img rev usemin manifest html:buildkit',
        basics    : 'usemin-handler rjs concat css min img rev usemin manifest html:basics',
        minify    : 'usemin-handler rjs concat css min img rev usemin manifest html:compress',
        test      : 'usemin-handler rjs concat css img rev usemin manifest'
    };

   // If we clobber targets, we have to rebuild targetList, the below is copy paster from Yeoman.js
    var targetList = grunt.log.wordlist(Object.keys(targets));

    // We also have to rebuild the build task with the new targetList
    grunt.registerTask('build', 'Run a predefined target - build:<target> \n' + targetList, function(target) {
        var valid = Object.keys(targets);
        target = target || 'usemin';

        if ( valid.indexOf( target ) === -1 ) {
            grunt.log
                .error('Not a valid target')
                .error(grunt.helper('invalid targets', targets));
            return false;
        }

        var tasks = ['intro', 'clean coffee compass mkdirs', targets[target], 'copy time'].join(' ');

        // Conditionally remove compass / manifest task if either compass or
        // phantomjs binary is missing. Done only for `test` target (specifically
        // used for our `npm test`). For each, output warning infos.
        if( target === 'test' ) {
            tasks = grunt.helper( 'build:skip', tasks, 'compass' );
            tasks = grunt.helper( 'build:skip', tasks, 'phantomjs', 'manifest' );
        }

        grunt.log.subhead('Running ' + target + ' target')
            .writeln('  - ' + grunt.log.wordlist(tasks.split(' '), { separator: ' ' }));


        grunt.task.run(tasks);
    });

@addyosmani - and yes, being able to do this like chris suggest with something like customTargets: { ... } would be awesome.

@hkdobrev
Copy link

hkdobrev commented Oct 8, 2012

I was just going to create a new issue about that. I was modifying yeoman.js and I got sick of it. With the automatic updating of Yeoman I had to update the build tasks after each update.

+1 for overriding the build targets (a.k.a sub-tasks).

@WickyNilliams
Copy link

Is there any scope for being able to register tasks a la grunt:

grunt.registerTask("myBuildConfig", "intro less min jasmine")

I know i can do this, and call yeoman myBuildConfig but I'd rather be able to call yeoman build:myBuildConfig to be consistent (or just yeoman build if i were able to override default)

@sindresorhus
Copy link
Member

You can override the default build task with your own:

grunt.registerTask('build','custom-task rjs concat css min img rev usemin manifest')

^ put in your gruntfile

@WickyNilliams
Copy link

D'oh! Hadn't even thought of approaching it from that angle! Thanks Sindre, please ignore my moronic ramblings :)

Just tested and it works a charm. Is there an equivalent for the server task? I see server:watch may be a good place to start, if i put my custom tasks in the watch config that may work?

@sindresorhus
Copy link
Member

Unfortunately the server task has hardcoded tasks, so it's not that easy, but we're working hard on making it supereasy to be able to customize.

@WickyNilliams
Copy link

Yeah I had seen various issues raised relating to that, when that is done I will be a very happy man!

With a little tinkering i have found a suitable workaround - it seems that yeoman server:reload can give me what i want. e.g. say my desired custom server task is to compile less files on change, given the (slightly simplified) watch config below:

watch: {
      less: {
        files: [
          'app/less/**/*.less'
        ],
        tasks: 'less reload'
      }
    }

the web page is reloaded automatically whenever a change is detected! BOOM! The only slight downside is that i must manually open the browser at port 35729 when first running the command, but that is tolerable for now :)

@addyosmani
Copy link
Member

@sindresorhus should we make a note about your comment above (#491 (comment)) in the docs, or will how you override the build target change in the next version of Yeoman?.

@sindresorhus
Copy link
Member

@addyosmani It's already in the wiki under Customize. And yes, it will change considerably in the next version.

@addyosmani
Copy link
Member

Awesome. Thanks for confirming :)

@WickyNilliams
Copy link

Cheers guys, good to hear there's still plans in place for improving this. Might it be worth adding my comment about the server task to the wiki also? It affords you some flexibility with the server task so that i'm now able to get LESS files compiled as part of it, whereas it's not possible by default.

@sattes-faction
Copy link

I just added

grunt.registerTask('build','rjs concat css min img rev usemin manifest');

which should just be the same task as the default build task. But when I run yeoman build I now get an error saying

<WARN> ENOENT, no such file or directory '/srv/htdocs/app/index.html' Use --force to continue. </WARN>

It seems to move one folder up, because the index.html is located in srv/htdocs/test/app/index.html and the Gruntfile is in srv/htdocs/test.

If I comment it out again it works.

@spacenick
Copy link

I had the same problem as @sattes-faction when overriding like this:

  grunt.registerTask('build','rjs concat css min img rev usemin manifest');

However if I write something like that:

  grunt.registerTask('build','intro clean coffee compass mkdirs rjs concat css min img rev usemin manifest copy time')

intro, clean, coffee, compass & mkdirs tasks will run fine. But now the rjs is raising another error :

Error: Missing either an "out" or "dir" config value. If using "appDir" for a full project optimization, use "dir". If you want to optimize to one file, use "out".

I'll try to dig a bit and see what's happening there. +1 for this issue though

@spacenick
Copy link

@sattes-faction ok in fact you need to call "usemin-handler" before rjs actually, in order to let him parse your rjs config. Everything runs fine for me when I add it.

@sleeper
Copy link
Contributor

sleeper commented Dec 11, 2012

usemin-handler prepares your configuration for rjs, min, concat and so on ... so yes needed, before them ;)

@sattes-faction
Copy link

@spacenick great, thanks for fiddling around with this. This works! 👍

@davidpelaez
Copy link

For everyone trying to customize yeoman's server, the best way isn't as the FAQ currently states (renaming the server task and putting something before). The best way is actually to override clean and run something AFTER that task, like this:

  grunt.renameTask('clean', 'original-clean');
  grunt.registerTask('clean', 'original-clean jade');

The reason is that if you want to compile something to temp instead of putting it inside app (like Handlebars and Jade) the clean task will wipe it all away and since the server is kept alive by Yeoman, any task you put after the server task won't be run, ever. So, if you need to do some compiling, like the coffee task, and keep your app folder clean then this is the way to go.

@sindresorhus I guess this is the simplest way I can think of to customize the server until a newer version with a better solution arrives.

@hkdobrev modifying yeoman is really really annoying indeed! I even created a wiki entry for that but it's very uncomfortable with the updates and I'm now changing that to this other method.

PS: I included this method in the FAQ and I'm currently updating the wiki page cited above so that people new to yeoman (like me) don't encounter the problem of including new modules to their apps in the server task.

@ghost ghost assigned sindresorhus Dec 28, 2012
@pixelhandler
Copy link

@spacenick yeah that works for me, i'm using ...

grunt.registerTask('build','intro clean coffee compass mkdirs usemin-handler rjs concat css min img rev usemin manifest copy time');

@sindresorhus
Copy link
Member

This is now possible in 1.0 which will be out soon.

@WickyNilliams
Copy link

Thanks Sindre! Would you be so kind as to report back when it is out (mainly so i get an email notification :)?

@sindresorhus
Copy link
Member

I most likely won't remember, but follow yeoman on twitter or g+ and you'll get it ;)

@WickyNilliams
Copy link

I may already be doing just that!

So is this server configuration entirely dependent on yeoman v1, or will yeoman v1 simply include the latest iteration of the server grunt task which offers this functionality?

@sindresorhus
Copy link
Member

It will include grunt-contrib-connect, but we use it combination with grunt-contrib-livereload.

@WickyNilliams
Copy link

Thanks, look forward to checking it out.

@paynecodes
Copy link

Could someone update me on this please. I have spent all day trying to find a solution without asking here but....I can't figure it out.

Here is my SO question as well. http://stackoverflow.com/questions/18449591/multiple-build-folders-multiple-clients-using-grunt

@davidpelaez
Copy link

I just replied to your SO question. Basically you can just register new
tasks in the middle, build is just a list of tasks to perform in order.

On Mon, Aug 26, 2013 at 5:04 PM, jpdesigndev notifications@github.comwrote:

Could someone update me on this please. I have spent all day trying to
find a solution without asking here but....I can't figure it out.

Here is my SO question as well.
http://stackoverflow.com/questions/18449591/multiple-build-folders-multiple-clients-using-grunt


Reply to this email directly or view it on GitHubhttps://github.com//issues/491#issuecomment-23298905
.

David Peláez Tamayo
Designer & Entrepreneur

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests