Skip to content

Cookbook: Creating a Rupert Plugin

Matthew Vita edited this page Jan 18, 2015 · 7 revisions

In Progress

Rupert Plugins allow third-party developers a convenient way to expose their library to Rupert. Rupert plugins usually perform by adding configuration information to Rupert, but can also reach in and modify behaviors of Rupert and Stassets in an aspect-oriented way (sometimes called "monkey patching").

Rupert finds plugins by looking for npm dependencies with rupert-plugin- as a module name prefix, and also by looking at the plugins key of the config object. Rupert will require the main file in the package, and expects a function returned. That function will get called with the config object.

Production

This pattern will cover most third party integrations. Add the local dependencies folder (node_modules) to the vendors prefix. Add each file as needed in the vendors arrays.

module.exports = function(config){
  // Use `config.find` to set or update properties
  // Use `config.prepend` and `config.append` to extend lookup arrays

  // Add the local relative node_modules to [stassets.vendors.prefix](https://github.com/RupertJS/rupert/wiki/Cookbook:-Add-Vendor-Libraries)
  config.append('stassets.vendors.prefix', [
    Path.resolve(__dirname, '../node_modules')
  ]);

  // Load jquery before other dependencies
  config.prepend('stassets.vendors.js', [
    'jquery/dist/jquery.js'
  ])

  // Load bootstrap after dependencies
  config.append('stassets.vendors.js', [
    'bootstrap/dist/js/bootstrap.js'
  ])

  // Load Bootstrap css after other vendors.
  config.append('stassets.vendors.css', [
    'bootstrap/dist/css/bootstrap.css',
    'bootstrap/dist/css/bootstrap-theme.css'
  ]);
};

Testing

When additional configuration settings are needed for the Testing environment, a Rupert plugin can additionally export a Gruntfile function. It will get passed the Grunt configuration (with grunt-recurse available, so assign to grunt.Config), as well as the rupert-grunt configuration to override and augment any Rupert Grunt details.

module.exports.Gruntfile = function(grunt, config){

};

Registering Custom Plugin

plugins.dependencies

If plugins is unavailable in the server.json configuration, package.json will get loaded. Either way, the dependencies hash will be consulted. The keys of the dependencies hash can either be rupert-grunt- module names (which must be installed via npm) or file paths (which have at least one / character). The module or file will be included, and executed as above.

As a local file

Place [file-path]: true in the plugin dependencies hash. true is sufficient as a key.

As an NPM module

Prefix with rupert-plugin-, publish to NPM, and please be a good citizen :) If this is a one-off module you don't intend to maintain, please notify a RupertJS team member and add at least one as a collaborator on the project. Consider asking the RupertJS team to move the plugin into the Rupert organization. If you intend to continue to maintain the package, consider adding davidsoutherci as an owner on the NPM registry, so that if you are unavailable to fix a critical issue the RupertJS CI server can push hotfixes when you're just getting on a plane for your honeymoon (this has actually happened).

Follow the steps here to include the custom plugin, making sure step #3 is satisfied. If the plugin is published, you can npm install --save rupert-plugin-custom-plugin. If the plugin is not published but is an NPM module, you can npm install --save /path/to/rupert-plugin-custom-plugin.

Testing a Rupert Plugin

Advanced

Adding a renderer

Rupert and Stassets can be extended by adding additional file types for js, css, and html transpilation. Stassets' constructor types for Script, Template, and Style have static renderers objects. Any key on the renderers will be used as a file extension, and when files of that type update Stassets will pass the raw file content (in utf-8) and the relative file path to the renderer function. The return value of the function should resolve (either a promise that resolve, or be the value) of an object with properties content, sourceMap, and path. content should be the utf-8 transpiled JS, CSS, or HTML; sourceMap should be a Javascript Source Map object (version 3), and path should be the passed path value as a nonce.

ScriptWatcher = require('rupert').Stassets.constructors.Script;

Script.renderers['es6'] = function(code, path){
    // Do something to render `code` into `content`, while generating `sourceMap`.

    return Q.when({content, sourceMap, path});
};