-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Asynchronous configuration #783
Comments
+1 |
1 similar comment
+1 |
You could try using https://github.com/gruntjs/grunt/wiki/grunt.task#grunttaskrun grunt.registerTask('default', function() {
var done = this.async();
//do your async config...
setTimeout(function() {
//equivalent to running grunt foo bar on the cli
grunt.task.run(['foo','bar']);
done();
});
}); Untested, though should work Note, you could use |
I'll give another example where this would be useful. I'm working on oasis.js, MessageChannel.js and conductor.js. They use components I install with bower. In fact, MessageChannel.js is a dependency of oasis.js which is a dependency of conductor.js. I want to do things with the main bower files, like concatenate them and copy them. In particular I want to "concatenate all vendor files". I don't want to have to manage a list of manual paths that will change when upstream dependencies change. Fortunately, bower provides an api to deal with this. But it's asynchronous, so I can't easily add the output from bower's API to the conductor Should I be organising these grunt builds differently? Should this be a bower concern (ie to provide a synchronous API)? |
It occurs to me that something i could do is use ShellJS and call |
Maybe the simplest solution for you would be to create an async If you do want to get fancy, you could modify the task queue, so Though these are just workarounds, as I think this is a legitimate issue, asynchronous config would come in handy, so the real solution is for grunt to implement a |
+1 I have a similar issue where I'm using data from an API that provides environment data for specific instances of a project that is then used to configure speicific tasks. I haven't found a way around it other than storing a copy of the data locally. |
+1 I'd like to be able to read data from files to init the grunting, see http://stackoverflow.com/questions/19831266/grunt-initconfig-in-a-callback-does-not-work/19836024 |
👍 It would be awesome if |
How would that work? The |
Because there is no grunt.start() drive the grunt, so must be one task registered at init time. |
I think all should be as a grunt task inlcude the Gruntfile, then we could force Gruntfile into async mod using function findSomeFilesAndPaths(callback) {
// async tasks that detect and parse
// and execute callback(results) when done
}
module.exports = function (grunt) {
// Force Gruntfile into async mode.
var done = this.async();
var config = {
pkg: grunt.file.readJSON('package.json'),
}
findSomeFilesAndPaths(function (results) {
config.watch = {
coffee: {
files: results.coffeeDir + "**/*.coffee",
tasks: ["coffee"]
// ...
}
done();
};
grunt.initConfig(config);
grunt.loadNpmTasks "grunt-contrib-coffee"
// grunt.loadNpmTasks(...);
});
}; |
@dnutels It could look something like this: module.exports = function(grunt) {
var configPromise = getConfigBasedOnFileSystemContents();
// either this
configPromise.then(grunt.initConfig);
// or this
grunt.initConfig(configPromise);
// in this case, no grunt tasks would be run until configPromise is resolved.
}; Does that address what you're looking for? |
@NickHeiner That's what I thought you had in mind. You'd need a finer granulation though - per task, probably, rather than per entire config. And without having to envelope all tasks in custom task and muck around with |
I would be a little cautious about the finer granulation - if you see something like grunt.initConfig({
copy: somePromise,
clean: someSettings
}); How do you know that I think it would be clearer to just do it all at once: q.all([getTaskAConfig, getTaskBConfig]).spread(function(taskAConfig, taskBConfig) {
grunt.initConfig({
'task-a': taskAConfig,
'task-b': taskBConfig,
'task-c': {
foo: 'bar'
}
});
}); Now there is no ambiguity. |
+1. |
👍 |
1 similar comment
+1 |
More than two years later and still not addressed. Huh. |
@NickHeiner @dnutels - an alternate way that I would expect for asynchronous config is adjust the handling for gruntfiles and task files. Gruntfiles export an function export that takes in a grunt object parameter, and when invocation of that export is complete, that file's processing is currently deemed 'complete'. However, we could also check to see if the exported function returned a promise, and condition completion on that. For example, here is how it is today: module.exports = function(grunt) {
// Project configuration.
grunt.initConfig(...);
// Load tasks from a plugin.
grunt.loadNpmTasks(...);
// register some tasks
grunt.registerTask(...);
// when this function returns, processing is considered complete for this file
}; An async version could look like: module.exports = function(grunt) {
return doSomethingAsync()
.then(function() {
// Project configuration.
grunt.initConfig(...);
})
.then(function() {
// Load tasks from a plugin.
grunt.loadNpmTasks(...);
})
.then(function() {
// register some tasks
grunt.registerTask(...);
});
// when the returned promise completes, processing is considered complete for this file
}; IMHO, this format is very recognisable to any programmer who is familiar with Promise-based asynchrony. By the way, I was annoyed by this limitation because I wanted to dynamically generate targets to a multitask, and the steps needed to generate it were only available via async APIs. So instead, the tasks are not a multi-task, which is kind of sad that it can't be done via the natural From an ecosystem approach, learning to respect returned promises is technically a breaking change - though probably small. I don't expect many gruntfiles intentionally return a Promise that was intended to be ignored/dropped the the floor by grunt. |
The docs say that I can programatically setup my configuration when (or before) calling grunt.initConfig(). Now I do very complicated stuff to dynamically initialize grunt (figuring out paths by parsing PHP-sources, downloading and decompressing archives, ...).
The problem is that my setup routine works asynchronously and must be completed before I call grunt.initConfig(), which obviously doesn't support asynchronous execution. Is there a way to defer the call until my callback has been fired?
More on this here:
http://stackoverflow.com/q/16547528/382597
Thank you!
The text was updated successfully, but these errors were encountered: