grunt-nautilus

Build modular javascript applications and frameworks that make sense

grunt-nautilus

Build modular javascript applications and frameworks that make sense

This plugin requires Grunt ~0.4.0

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin in one of two ways:

The recommended install is via the init template. Checkout grunt-init-gruntnautilus for info on installing the template and how to use it. The other way is to simply install with npm and configure your Gruntfile:

npm install grunt-nautilus --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

grunt.loadNpmTasks( "grunt-nautilus" );

This plugin loads a handful of other grunt plugins as peer dependencies. If you're using this plugin, you won't need to load any of the following yourself:

Run this task with the grunt nautilus command.

Task targets, files and options may be specified according to the grunt Configuring tasks guide.

This is the recommended default task implementation and also what you'll see in your Gruntfle if you used the init template:

grunt.registerTask( "default", ["nautilus:build"] );

This plugin has some reserved task arguments. You can think of them as super-powered task configuration that you don't have to configure yourself.

For development sandbox modes this argument runs nautilus core without uglification.
Tasks: jshint, concat, clean, compass, ender

For real world environments, this argument runs nautilus core with uglification.
Tasks: jshint, uglify, clean, compass, ender

This argument creates templated module files for you using the es6 module syntax.

There are a few optional flags available when working with grunt-nautilus.

Type: String
Default: undefined

This flag is used alongside the module argument to create new modules, grunt nautilus:module --path foo/bar. This makes a new module for you at /path/to/your/app/foo/bar.js.

Type: Boolean
Default: undefined

Tell grunt-nautilus to log everything it is doing. This is handy for development of the plugin and for understanding how the plugin works from a user's perspective. But, ultimately, these logs will become cumbersome to see and you likely won't want this running all the time.

Type: String
Default: undefined

Tell grunt-nautilus to use this specified environment for executing compass on build and deploy.

These are the supported options for this plugin. It may be helpfull to glance over an example of a Gruntfile with all available options and configuration specified to get an idea of what all you can let grunt-nautilus handle for you.

Type: String
Default: undefined

Specifies the target js directory.

Type: String
Default: undefined

Specifies the target app directory within the js root.

Type: String
Default: undefined

Specifies the target lib directory within the js root.

Type: String
Default: undefined

Specifies the target dist directory within the js root.

Type: String
Default: undefined

Specifies the target public resources directory. Your js root is usually in this directory.

Type: Object
Default: js{app: true, console: true, module: true}

Same as jshint.options.globals. Your globals will be merged with the defaults.

Configuration to be used with [grunt-sails-linker][].

Type: Array
Default: js["app.js", "controllers/**/*.js"]

Specifies target control js relative to jsAppRoot. Your dist files are compiled from these.

Type: Array
Default: undefined

A list of tasks that you would like js linting to occur on.

Type: Array
Default: undefined

A list of non-app files that you would like js linting to occur against.

Type: Object
Default: undefined

Set this with cssRoot and sassRoot properties if you would like compass configured and compiled using grunt-contrib-compass.

Type: Array
Default: []

Add file names here, extensionless and relative to the app javascript directory, to be compiled to dist without the app object compiled on top of them.

The jsGlobals option is an object that will be merged with jshint.options.globals.

grunt.initConfig({
    nautilus: {
        options: {
            jsGlobals: {
                $: true,
                jQuery: true
            }
        }
    }
});

The hintOn option specifies tasks you want linting to run on. The hintAt option specifies files outside of your authored app you want to be linted.

grunt.initConfig({
    nautilus: {
        options: {
            hintOn: [
                "watch",
                "build",
                "deploy"
            ],
            hintAt: [
                "lib/plugins/**/*.js"
            ]
        }
    }
});

This is a helpful example of all the options and configuration grunt-nautilus will work with. The ender config is totally optional. If the ender config is present than grunt-nautilus will execute your ender build on every build/deploy task execution ensuring your dist js is always up to date with your latest ender config.

module.exports = function ( grunt ) {
    var pubRoot = ".",
        sassRoot = "./sass",
        cssRoot = "./css",
        fontsRoot = "./fonts",
        imgRoot = "./img",
        jsRoot = "./js",
        appRoot = jsRoot+"/app",
        libRoot = jsRoot+"/lib",
        distRoot = jsRoot+"/dist";
        
    grunt.initConfig({
        // Nautilus config. 
        nautilus: {
            options: {
                hintAt: [],
                hintOn: [
                    "watch",
                    "build",
                    "deploy"
                ],
                jsAppRoot: appRoot,
                jsDistRoot: distRoot,
                jsGlobals: {
                    $: true,
                    ender: true
                },
                jsLibRoot: libRoot,
                jsRoot: jsRoot,
                main: [
                    "myApp.js"
                ],
                pubRoot: pubRoot,
                compass: {
                    cssRoot: cssRoot,
                    sassRoot: sassRoot,
                    imgRoot: imgRoot,
                    fontsRoot: fontsRoot
                }
            }
        },
        // Ender config. ( optional ) 
        ender: {
            options: {
                output: libRoot+"/ender/ender",
                dependencies: ["jeesh"]
            }
        }
    });
    
    grunt.loadNpmTasks( "grunt-nautilus" );
    
    grunt.registerTask( "default", ["nautilus:build"] );
};

This plugin uses the es6-module-transpiler to parse es6 syntax within your application files. This means you get to write clean, modular applicational code that compiles into a full application object for the browser. I highly recommend checking out the documentation on supported es6 syntax for the module. This plugin supports all syntax the module supports but implements a custom compiled output. The globals output is used internally, however it undergoes extra parsing to output a clean application object to the global scope of the browser document.

Any application schema can be created using the app argument and passing it any number of additional arguments. The arguments are parsed into a directory path with the last argument being the module js file. A core application file will preceed all your modules in the dependency stack for dist js builds. This file creates the base global app that is used for the custom compiled output of your application. You can review that core file here.

Module import paths will be relative to your jsRoot option:

  • import { baz } from "app/foo/bar/baz";
  • import "lib/ender/ender";

In terms of looking up module imports, grunt-nautilus will look in the following places: jsAppRoot, jsRoot, pubRoot and lastly from the Gruntfile location. This should be more than enough in terms of application organization in conjunction with using third party package managers like npm or bower. When using third party imports that don't utilize the es6 export syntax, grunt-nautilus will try to find a global to match it to. A config of popular js libs is maintained internally to try to do this. If your import is not found there, the jsGlobals option will be referenced. If no match is found, the import will be assumed global and included in the dist stack but not sandboxed into the current modules closure.

To create a new index controller module for you application run the following:

grunt nautilus:module --path "controllers/index"

A new module controller will be generated for you at app/controllers/index.js within your jsRoot.

var index = {
    initfunction () {
        
    }
};
 
export default = index;

Now run grunt nautilus:build and you're controller will compile to this:

(function( windowdocumentundefined ) {
  "use strict";
  
  var index = {
      initfunction () {
          
      }
  };
 
  window.app.controllers.index = index;
})( window, window.document );

Now add an import, say you're managing your jQuery build with bower:

import "bower_components/jquery/jquery";
 
var index = {
    initfunction () {
        
    }
};
 
export default = index;

Which will compile to the following, sandboxing jQuery as $ into your closure for this module and ensuring jQuery is compiled into your dist js above your module in the stack:

(function( windowdocument$undefined ) {
  "use strict";
  
  var index = {
      initfunction () {
          
      }
  };
 
  window.app.controllers.index = index;
})( window, window.document, window.jQuery );

You can directly assign a module to a variable for use in your application. This syntax would assume the baz module is an object with properties that can be individually imported:

import { bot } from "app/foo/bar/baz";
 
var index = {
    initfunction () {
        
    }
};
 
export default = index;

This will compile to the following:

(function( windowdocumentbazundefined ) {
  "use strict";
  
  var bot = baz.bot;
  
  var index = {
      initfunction () {
          
      }
  };
 
  window.app.controllers.index = index;
})( window, window.document, window.app.foo.bar.baz );

To put this in context, the baz module may look something like this:

var bot = "bot";
var bat = "bat";
 
export { bot, bat };

Alternatively, the global app object is assumed for you application and you can do plain imports and reference modules in a global scope manner as well:

import "app/foo/bar/baz";
 
var index = {
    initfunction () {
        console.log( app.foo.bar.baz );
    }
};
 
export default = index;

This is a nice way to import third party scripts like jQuery or ender where you would want the sandboxed $ as opposed to a variable assigned $.

  • 0.3.20 Stable early release
  • 0.4.0 Beta es6-module-transpiler release
  • 0.4.7 Stable es6-module-transpiler release