jakejs / jake

JavaScript build tool, similar to Make or Rake. Built to work with Node.js.
http://jakejs.com
Apache License 2.0
1.97k stars 190 forks source link

Is it possible to invoke a rule? #290

Closed blockloop closed 1 year ago

blockloop commented 9 years ago

I have a few rules that drive my Jakefile and I want my jake build task to loop source files and invoke the rule that matches that file. I've tried with jake.Task[file].invoke() and jake.Rule[file].invoke() and I'm getting an error saying TypeError: Cannot read property 'invoke' of undefined

rule('public/%.js', getSourceFileName, {async: true}, buildJsFile);

...
task('build', function() {
    var files = new jake.FileList();
    files.include('src/**/*.js');
    files.toArray().map(getDestFileName).forEach(function(file) {
        console.log('invoking %s', file);
        jake.Task[file].invoke(); // jake.Rule[file].invoke();
    });
});
invoking public/app.config.js
jake aborted.
TypeError: Cannot read property 'invoke' of undefined
    at /Users/bjones027/projects/ot/Apollo/Client/Jakefile.js:44:24
    at Array.forEach (native)
(See full trace by running task with --trace)

if I call jake public/app.config.js directly from cli it compiles properly.

Can I invoke a rule like this? Is there a better way to do this?

glastonbridge commented 8 years ago

I've not had time to dig into the code, but here is quick and oh-so-dirty workaround that seems to work okay within another task's body. It's not nice, use it at your own peril.

var fileLocation = "myFile.txt"; task("ruleMagicTask"+ fileLocation,[fileLocation]); jake.Task["ruleMagicTask"+fileLocation].invoke();

welearnednothing commented 8 years ago

@blockloop Maybe I'm missing something about your intended use, but typically those resulting files would be listed as prerequisite of the build task. For instance:

rule('public/amazing.js', ['src/foo.js', 'src/bar.js'], {async: true}, buildJsFile);

task('build', ['public/amazing.js'], function() {
  console.log('Crazy, right?');
});

Then when build is called, it will automatically check if src/foo.js or src/bar.js are newer than public/amazing.js. If so, public/amazing.js will be rebuilt via the buildJsFile function you've specified.

If you're dealing with a lot of files - either many target files or many source files that create a target file, you may need to come up with that list. Thankfully, since this is just Node, that's not too difficult in many cases - and Jake's FileList is very handy here, as well.

// We'll list every src file as a pre-requisite of build
var prereqs = new jake.FileList(['src/**/*.js']);
task('build', prereqs.toArray(), function() {
  console.log('Done!');
});

var getSourceFileName = (name) => name.replace('public', 'src');

rule(/public\/.*\.js$/, getSourceFileName, ['public'], function() {
  // Create the target directory. If you have a few known directories, you can
  // use predefined directory tasks outside of the rule and specify them as prereqs
  // instead. But if you have many directories as you may in your original example, this works.
  directory(path.dirname(this.name)).invoke();
  console.log(this.source + " -> " + this.name);
  fs.closeSync(fs.openSync(this.name, 'w')); // I'm writing a blank file. This is almost certainly not what you want
});

I'm going to look into improving the docs and files and rules so that it's easier to understand how they're intended to be used. They pretty powerful, but I had to play around with them for awhile to wrap my head around them.

Let me know if this helps solve the problem!