npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

gruntfile-gtx

v1.0.0

Published

Turbo, spoilers and a sunroof for your Gruntfile

Downloads

801

Readme

gruntfile-gtx

Build Status Coverage Status Dependency Status npm version

Turbo, spoilers and a sunroof for your Gruntfile.

Grunt enhancement to make gruntfile task management more dynamic and powerful. Handle demanding setups while keeping your Gruntfile shiny and DRY.

Features

  • Use macros to generate chains of related (semi-anonymous) plugin task instances.
  • Use tags to group and select similar targets.
  • Create new aliases by filtering tasks on various fields.
  • Transparently streamline gruntfile api a little.

Macros are powerful to define chains of targets for different plugins that together define a blueprint for build-sub-process. Create different instances that share or change parameters like identifiers, (partial) paths.

API Change

Per v0.1.0 the API was updated. The old docs can be found here

Usage

Check the Gruntfile for practical dogfooding and browse the tests for some more options.

Example

module.exports = function (grunt) {

  // get the gtx instance
  var gtx = require('gruntfile-gtx').wrap(grunt);

Load some plugins:

  gtx.loadNpm(
    'myPlugin',
    'myOtherPlugin'
  );
  //classic array
  gtx.loadNpm([
    'myPlugin',
    'myOtherPlugin'
  ]);
  // folder
  gtx.loadTasks('./tasks');
  
  // alternately load automatically (from ./tasks and ./node_modules)
  gtx.loadAuto();

Build the grunt config like the regular structure:

  gtx.config({
    // read and blend objects
    pkg: gtx.readJSON('package.json', {title: 'foo'}, './conf/overwrite.json'),
    myPlugin: {
      options: {
        //..
      },
      main: {
        src: ['./files/main/*.js']
      }
    },
    myOtherPlugin: {
      main: {
        src: ['./files/dev/*.js']
      }
    }
  });
  // ... but split over multiple statements
  gtx.config({
    myPlugin: {
      dev: {
        src: ['./files/dev/*.js']
      }
    }
  });
  // or directly set config objects
  gtx.configFor('myPlugin', 'beta', {
    src: ['./files/beta/*.js']
  });

Define tasks:

  // define a simple task
  gtx.call('say', function() {
    grunt.log.writeln('hello!');
  });

  // define a multi-task
  gtx.multi('alpha_multi', function() {
    var options = this.options({
      //..
    });
    grunt.log.writeln('hello!');
  });

Run tasks:

  // named serial
  gtx.alias('many', ['one', 'two', 'three']);

  // named concurrent (max cpu cores)
  gtx.concurrent('many', ['one', 'two', 'three']);

Generate a unique name for a configuration (this is the basis for the macro feature)

  var name = gtx.configFor('myPlugin', {
    src: ['./files/gamma/*.js']
  });

  // do creative stuff by generating tasks (go wild here)
  gtx.alias('bulk_run', ['one', 'two', 'three'].map(function (name) {
    return gtx.configFor('myPlugin', {
      src: ['./files/' + name + '.js']
    });
  }));

  // generated tasks from parallel() to run concurrently
  gtx.alias('many', ['one', gtx.parallel('two', 'three')]);

  // generated tasks from serial()
  gtx.alias('more', ['one', 
    gtx.parallel(
      gtx.serial('two', 'three'),
      gtx.serial('four', 'five'))
    )
  ]);

This example is lifted from the gruntfile of TSD and shows a macro to compile and run separated 'test modules'. These can also be run concurrently to cut-down on overall test-duration for IO heavy topics.

Note how the macro uses a few plugins to setup and run: it would be a hassle to maintain these modules in a regular gruntfile but it is easy when using a macro to build the instance:

  gtx.define('module_tester', function (macro, id) {
    // the macro object is a context with helpers to assemble a new instance named 'id'

    // let's use the instance id to build a shared path
    var testPath = 'test/modules/' + id + '/';

    // use grunt-contrib-clean to remove old test output
    macro.add('clean', [testPath + 'tmp/**/*']);

    // run a regular task
    macro.run('myPlugin:dev');

    // use grunt-ts to compile the TypeScript test cases
    macro.add('ts', {
      options: {},
      src: [testPath + 'src/**/*.ts'],
      out: testPath + 'tmp/' + id + '.test.js'
    });
    // use grunt-tslint
    macro.add('tslint', {
      src: [testPath + 'src/**/*.ts']
    });
    // optionally spawn a grunt-contrib-connect
    if (macro.getParam('http', 0) > 0) {
      macro.add('connect', {
        options: {
          port: macro.getParam('http'),
          base: testPath + 'www/'
        }
      });
      //tag for easy retrieval
      macro.tag('http');
    }
    // run grunt-mocha-test on the compiled test cases
    macro.add('mochaTest', {
      options: {
        timeout: macro.getParam('timeout', 2000)
      },
      src: [testPath + 'tmp/**/*.test.js']
    });
  }, {
    // optionally run parallel using grunt-concurrent (for now only from gtx-type)
    concurrent: 4
  });

Use the macro to make many similar instances:

  // use the macro to make many instances
  gtx.create('git', 'module_tester', null, 'lib');
  gtx.create('tsd', 'module_tester', {timeout: 10000}, 'lib,core');
  gtx.create('http', 'module_tester', {
    timeout: 20000,
    http: 8080
  }, 'lib');
  // bulk
  gtx.create('basic,remote,local', 'module_tester');
  gtx.create(['basic','remote','local'], 'module_tester');

Mix functions and id's:

  // mix calls in alias
  gtx.alias('mix', ['alpha:one', 'bravo:two', function() {
    grunt.log.writeln('roger');
  }, 'charlie', function() {
    grunt.log.writeln('roger');
  }]);

Finish up:

  // let's make an alias to run all instances as your $ grunt test
  gtx.alias('test', 'gtx-type:module_tester');

  // alias is short-cut for grunt.registerTask();
  gtx.alias('default', ['test']);

  // compile and send to grunt.initConfig()
  gtx.finalise();
};

To run these macro instances:

$ grunt -h
$ grunt gtx:git
$ grunt gtx-group:core
$ grunt gtx-group:http
$ grunt gtx-type:module_tester

// bonus: clean all
$ grunt clean

Additional examples:

  • Complex example from mocha-unfunk-reporter uses a macro to setup a CLI output bulk tester (this is also a warning about power and responsibility).

Info

  • Your gruntfile is still a regular gruntfile to run by grunt-cli.
    • Use the grunt -h command to view the generated tasks.
    • Main difference is to import and apply gruntfile-gtx on start if the Gruntfile.
    • Call gtx.finalise() at the end of the file to generate the config and apply aliases.
  • Generated aliases are prefixed with gtx, like gtx-select:myAlias or gtx-group:dev.
    • They run like any task created by grunt.registerTask().
  • The extra API sugar like gtx.loadNpm() is optional, but is generally DRY-er then the regular versions.
  • String input uses a form of expansion and iteration where applicable.
    • Split strings on separators to array: gtx.alias('name', 'one, two, three')
    • Nested arrays are flattened and the content split: gtx.alias('name', [['aa','bb'], 'cc', ['dd, ee'],'ff,gg,hh'])
    • Where grunt methods accept a single string the alias will iterate: gtx.loadNpm([..])
  • Gruntfile-gtx was grown organically: no gold-plating but some edges made shiny from wear.

Future

There a lot of ideas for this floating around for this, from auto-dependency chains and non-repeating macro util tasks, to globbing helpers to generate macro instances and flows adapting to custom cli parameters or env variables. Also it would be cool to interface with (Yeoman) generators for easy instancing of build sub modules.

Most of these wait until Grunt reaches 0.5.0 which solve some of the original problems.

API

See above usage examples and look at the Gruntfile and the tests for more usage.

Release History

See the CHANGELOG.

Contributing

Contributions are welcome (idiomatic, clean etc) but best to post a proposal in the Issues before making big changes.

License

Copyright (c) 2013-2018 Bart van der Schoor

Licensed under the MIT license.