David Bashford

A web dev blog from a Washington DC based Dad, UI architect, web developer, and creator of Mimosa.

    

Adhoc Modules: Custom Tasks & Baby Steps Towards Publishing Modules

The adhoc-module Mimosa module is real easy to use and makes adding custom build behavior a piece of cake. It is also a great gateway to learning how to build Mimosa modules that you wish to deploy to NPM for community use.

Need Truly Custom Behavior in Your Build?

Need some really specific functionality built into your Mimosa build? Maybe you need to do some install-time code manipulating. Or maybe you need to be able to swap out values of JavaScript properties based on your target environment. Possibly you have a deployable product and you need each deploy to vary slightly (different skin?) and you'd love Mimosa to handle that for you.

Until recently, you had three options:

  1. You could hope the task you need to perform was available as a module already. Most modules, though, are meant to be general in their function. So you might strike out quickly here.
  2. You could create your own module and stick it in NPM. That may not be desirable for you, though. You may not want to have to maintain it, and you may not want to expose any of what you might be doing at work in the form of a module.
  3. You could create a module locally, in your project or within your company's code repos, and mimosa mod:install it. This introduces another build step, though. Now all your developers have to make sure to mod:install a specific piece of code. And it means you may have another repo to manage.

Enter the Adhoc Module

The adhoc-module was released recently and it allows you to create modules within your code base and require them right into your project.

This module has a dead simple config:

adhocModule: {  
  modules: []
}

The modules array should contain required in stripped-down mimosa modules.

You would include adhoc modules like this:

adhocModule: {  
  modules: [
      require('./scripts/perform-transforms'),
    require('./scripts/deploy-to-heroku')
  ]
}

The paths above point at node code in the ./scripts directory. That code must expose a registration function that serves the exact same function as the registration function of any module you have plugged into your project.

In the case above, two modules are included. You can add as many as you wish.

What is registration?

For a complete rundown of how registration works, check the blog post on creating modules. That post is much larger in scope, though, so you may just want to keep reading, I'll cover it here in brief.

The registration function exposed by your adhoc modules is called as Mimosa is first starting up. It is a Mimosa module's (and adhoc module's) means to associate the execution of some code with a specific step in a Mimosa build.

The registration function is passed the mimosaConfig which contains the full configuration for your project's Mimosa process, including anything you've included in your own mimosa-config.js/coffee. The registration function is also passed a register function which when executed with the right parameters will notify Mimosa that it needs to call your code at a given point in Mimosa's processing.

register takes 4 parameters and when executed it plugs your code into the right place in Mimosa's processing.

  • The 1st parameter tells Mimosa during which build workflow the passed callback (3rd parameter) should be executed. The Mimosa web site covers all the various build workflows. Workflows include add/update/remove, buildFile, buildDone, and so on.
  • The 2nd parameter tells Mimosa what step during the workflow to execute the callback. Each workflow has a set of steps like beforeRead, afterCompile, and package. The complete set of workflow/steps can be seen by checking out the code.
  • The 3rd parameter is the callback. This should be a reference to a JavaScript function that contains the code you want to execute at the specific build workflow and build step. The callback is passed the mimosaConfig, an options object that contains information any files being currently processed, and a callback that is to be called when the module has finished its task.
  • The 4th parameter is optional. If your adhoc module is meant to process individual files, like JavaScript files, this parameter is your chance to make sure that your callback is only called with the right files. This parameter is an array of file extensions. Ex: ['html','htm'].

Using registration

At my day job we use adhoc modules extensively. Here's a quick registration function for one of our adhoc modules.

var _execute = function( mimosaConfig, options, next ) {  
  // do something
  next();
};

var _clean = ...

exports.registration = function( mimosaConfig, register ) {  
  if ( mimosaConfig.isBuild && mimosaConfig.isPackage ) {
    register( ["postBuild"], "beforeInstall", _execute );
  }
  register( ['preClean'], 'init', _clean );
};

You can see the registration function is only concerned with executing its code if the current process is a build (mimosa build) and if the --package flag has been used. In this case the _execute function is called during the beforeInstall step. This particular module (code omitted) performs transformations on server templates prior to deployment. Server-side code isn't usually in Mimosa's wheelhouse, but there's nothing stopping a Mimosa module from reading from the file system, making changes and writing back.

This particular module also registers for the preClean step during which any assets it may have been responsible for writing during the postBuild step can be cleaned up.

Use it to Learn How to Build Modules!

Using adhoc-modules locally is a great way to learn how to build larger modules that you may intend to distribute. It's super easy to get started.

Just toss some code in a directory in your app, add adhoc-module to your node modules, wire up the config and you are off and running. The hardest part to master is determining when to run your code. A little trial-and-error, printing out the options object will help out there.

comments powered by Disqus