RequireJS

Grunt RequireJS Example

1. Grunt

The main pre requisite that you need in order to follow this example is to have NodeJS installed in your environment. You can check the installation instructions here https://nodejs.org/en/.

Grunt is a JavaScript based task runner. It is quite simple to use since everything is about configuring what tasks you want to execute and in what order. You can specify all these tasks in a single Grunt file configuration. One of the keys about Grunt success is its amount of available plugins (http://gruntjs.com/plugins). For more information about grunt please visit http://gruntjs.com/.

The first step is to install Grunt within your NodeJS installation. Here you can find the proper instructions: http://gruntjs.com/getting-started.

2. RequireJS

RequireJS is an AMD JavaScript library that supports asynchronous file and module loading. It is optimized for web browser usage but it is also possible to use in Java or Node environments. It is compatible with all main browsers and quite intuitive to use. Its main benefit is that it offers the option to logically structure an application following the AMD principles.

In the article https://www.webcodegeeks.com/javascript/requirejs/requirejs-tutorial-how-to-use-requirejs/ you can find more information about how to use RequireJS.

3. Grunt with RequireJS

In this example we are going to show how to create an application that uses RequireJS in combination with Grunt. We will use Grunt to download and install the needed RequireJS packages and to generate the desired deliverables.

The first step is to install the RequireJS Grunt plugin, you can do that by typing in your NodeJS console:

npm install grunt-contrib-requirejs --save-dev

if you want to check that the installation has been successful, you can type:

npm ls

And something like the following should appear:

`-- grunt-contrib-requirejs@1.0.0
  `-- requirejs@2.1.22

If this is the case, you are ready to go!

4. Example

This is going to be a real life example showing a foreign exchange calculator. The application contains a home page where users enter a base and target currency and an amount and the application returns the used rate and the result applying this rate to the passed amount. The examples modules are shown here:

HTML view:

index.html

//check download section to see HTML code

    $(".fxcalculation").click(function(event)
    {
        var fromCur = $(".fx1").val();
        var toCur = $(".fx2").val();
        var amountFrom = $(".fxamount").val();
        var result = fxApp.rate(fromCur, toCur, amountFrom); //created in the wrap.start snippet
        $(".fxrate").html(result.rate);
        $(".fxresult").html(result.total);
        return false;
    });


Main JavaScript file acting as controller:

App.js

define([
    "jquery",
    "fx/DataConnector",
    "fx/Calculator"
], function($, DataConnector, Calculator)
{
    'use strict';

    var fxApp = {};

    /**
     * Calculates from to and puts result in a label
     */
    fxApp.rate = function()
    {
        var fromCur = $(".fx1").val();
        var toCur = $(".fx2").val();
        var amountFrom = $(".fxamount").val();
        var fxRate = DataConnector.retrieveData(fromCur, toCur);
        var amountTo = Calculator.calculate(amountFrom, fxRate);
        $(".fxrate").html(fxRate);
        $(".fxresult").html(amountTo);
        return false;
    };

    return fxApp;

});

The module bellow takes care of calculations and currency normalizations:

Calculator.js

define([], function()
{
    'use strict';

    var calculator = {};
    /**
     * very complicated calculations are part of this method
     * @param amount
     * @param rate
     * @returns {number}
     */
    calculator.calculate = function(amount, rate)
    {
        return amount * rate;
    };
    return calculator;
});

The following snippet shows a module taking care of the data retrieval for the foreign exchange rates:

DataConnector.js

define([], function () {
    'use strict';

    var connector = {};
    /**
     * data retrieval to get fx rate for a given currency pair (fake)
     * @param from
     * @param to
     * @returns {number} fx rate
     */
    connector.retrieveData = function (from, to) {
        var rate = 1;
        if ("EUR" === from) {
            if ("USD" === to) {
                rate = 1.5;
            }
            else if ("GBP" === to) {
                rate = 0.5;
            } else if ("CHF" === to) {
                rate = 0.24;
            }
        } else if ("USD" === from) {
            if ("EUR" === to) {
                rate = 0.5;
            }
            else if ("GBP" === to) {
                rate = 0.25;
            } else if ("CHF" === to) {
                rate = 1.24;
            }
        } else if ("GBP" === from) {
            if ("EUR" === to) {
                rate = 1.5;
            }
            else if ("USD" === to) {
                rate = 1.75;
            } else if ("CHF" === to) {
                rate = 1.33;
            }
        } else if ("CHF" === from) {
            if ("EUR" === to) {
                rate = 1.22;
            }
            else if ("USD" === to) {
                rate = 3.75;
            } else if ("GBP" === to) {
                rate = 6.33;
            }
        }
        return rate;
    };
    return connector;
});

The RequireJS configuration with the used options, for a full list of options available please visit the tutorial https://www.webcodegeeks.com/javascript/requirejs/requirejs-tutorial-how-to-use-requirejs/:

main.js

requirejs.config({
    baseUrl: 'js',
    waitSeconds: 20,
    paths: {
        "jquery": "jquery"
    },
    deps: ['fx/App'],

    urlArgs: "t=20160320000000"
});

And finally, the grunt file, where the configuration options are listed and the deliverables are created using the RequireJS Grunt plugin:

gruntfile.js

module.exports = function (grunt) {

    // Project configuration.
    grunt.initConfig({

            //package json containing needed Grunt plugins
            pkg: grunt.file.readJSON('package.json'),

            //require js configuration
            requirejs: {
                build: {
                    options: {
                        baseUrl: "js",
                        mainConfigFile: "js/main.js",
                        name: "almond", //using almond plugin to generate deliverable
                        include: ["fx/App"],
                        wrap: {
                            "startFile": "js/wrap.start", //wrapping before deliverable
                            "endFile": "js/wrap.end" //wrapping after deliverable
                        },
                        optimize: 'none', // none / uglify2
                        "out": "build/FxCalculator.js"
                    }
                }
            },

            //small tidy up task
            clean: {
                start: [
                    'build/*'
                ]
            }
        }
    );

    grunt.loadNpmTasks('grunt-contrib-requirejs');
    grunt.loadNpmTasks('grunt-contrib-clean');

    // Default task(s).
    grunt.registerTask('default', [
        'clean:start',
        'requirejs:build'
    ]);

};

The file above uses the following package.json:

package.json

{
  "name": "ForeignExchangeCalc",
  "version": "0.0.1",
  "description": "Module for foreign exchanges calculations",
  "dependencies": {},
  "devDependencies": {
    "grunt-contrib-requirejs": "~0.4.4",
    "grunt-contrib-clean": "^0.7.0"

  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Dani Buiza",
  "license": ""
}

Since we are using almond.js in our configuration we put a start and end snippets around our deliverable so the module is exposed globally:

wrap.start

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD.
        define(['jquery'], factory);
    } else {
        // Browser globals
       root.fxApp = factory(root.$);
    }
}(this, function ($) {

wrap.end

    //Register in the values from the outer closure for common dependencies
    //as local almond modules
    define('jquery', function () {
        return $;
    });

    //Use almond's special top-level, synchronous require to trigger factory
    //functions, get the final module value, and export it as the public
    //value.
    return require('fx/App');
}));

In order to generate the desired deliverables you just need to type in (where the grunt configuration file is located):

npm install

in order to install all required NodeJS modules and

grunt

in order to generate the deliverables. At the end you can open the index.html file in a browser and see the results.

5. Summary

That’s it. In this example we briefly explained what Grunt and RequireJS are, we listed very useful internal and external resources and we provided a working example that shows how to deliver a RequireJS application using Grunt and the almond.js plugin.

6. Download

Download
In the following link you can download a full working example covering the main components explained in this article: requireJsGruntExample.zip

7. Links

You can find more in deep information about Grunt, RequireJS or NodeJS in the following links:

Dani Buiza

Daniel Gutierrez Diez holds a Master in Computer Science Engineering from the University of Oviedo (Spain) and a Post Grade as Specialist in Foreign Trade from the UNED (Spain). Daniel has been working for different clients and companies in several Java projects as programmer, designer, trainer, consultant and technical lead.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button