How to manage bower dependencies with Grunt

How to manage bower dependencies with Grunt

In this article we will describe how to manage bower dependencies with Grunt in your html file.

By managing the bower dependencies i mean, insert automatically bower dependencies in the html file by executing a Grunt command line.

What i want to manage

This is a list of things i want to do :

  • Automatically insert the <script /> and <link /> tags in my index.html file for each dependencies i have in my bower file
  • Update (automatically) the file when i add a bower dependency

Installing tools

I assume you already have node.js installed on your system, if not, simply go to the node.js website and follow the instructions.

If you already have Grunt and bower installed no need to do the following steps.

In order to install the needed tools run the following command :

npm install -g bower grunt-cli

Creating the project

Now we will create the main application structure like that :

cd PATHTO/project
mkdir app

Then create the file index.html in the app directory :

app/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Cool Title</title>
</head>
<body>

</body>
</html>

Then we will create the node.js package.json file :

package.json

{
  "name": "projectName",
  "version": "0.0.1",
  "author": "Remi goyard",
  "license": "MIT",
  "description": "The Cool Description",
  "repository": {
    "type": "git",
    "url": "http://github.com/"
  },
  "engines": {
      "node": ">= 0.10.0"
  }
}

In order to create that package.json file you can use the command npm init at the root of your project directory.

Then create the bower.json file :

bower.json

{
  "name": "projectName",
  "version": "0.0.1",
  "author": "Remi goyard",
  "license": "MIT",
  "description": "The Cool Description",
  "main": "",
  "homepage": "",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components"
  ]
}

In order to create that bower.json file you can use the command bower init at the root of your project directory.

Adding dependencies

Ok, now we will add the bower dependencies, imagine, for example, you want to add Bootstrap and the Js implementation.

bower install boostrap asciidoctor.js --save

This will create a bower_components directory in your project.

So now if you want to use the new installed components in your index.html file you will have to manually add the links, something like that :

app/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Cool Title</title>
    <link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap-theme.min.css" />
</head>
<body>


<!-- JavaScript Files -->
<script src="../bower_components/jquery/dist/jquery.js"></script> (1)
<script src="../bower_components/bootstrap/dist/js/bootstrap.js"></script>
<script src="../bower_components/opal/opal/current/opal.js"></script> (2)
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-all.min.js"></script>
</body>
</html>
  1. jQuery dependency required by booststrap
  2. Opal is required by Asciidoctor.js

So now you can use your dependencies.

As you can imagine if you add a bower dependency you will have to manually add the files in your index.html file.

Automatic insertion

As I said at the top of the post, I would prefer to automatically update the index.html file when I add a dependency. We will use Grunt and the grunt-bower-install plugin.

First we need to create the Gruntfile.js, here is a minimal one :

Gruntfile.js

/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({

    // Tasks
  });


  // Default task.
  grunt.registerTask('default', []);

};

As usual you can also create the Gruntfile.js file by using the grunt-init command.

As this, the file is not very useable, we need to add the grunt-bower-install plugin :

npm install grunt-bower-install --save-dev

This will add the grunt-bower-install plugin in the package.json file. And now you can create the grunt task for the plugin :

Gruntfile.js

/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({

    bowerInstall: {

      target: {
        src: [
          'app/index.html'   // .html support...
        ],

        // Optional:
        // ---------
        cwd: '',
        dependencies: true,
        devDependencies: false,
        exclude: [],
        fileTypes: {},
        ignorePath: '',
        overrides: {}
      }
    }
  });

  grunt.loadNpmTasks('grunt-bower-install');
  // Default task.
  grunt.registerTask('default', ['bowerInstall']);

};

Then edit the index.html file to insert the tags used by the grunt-bower-install plugin :

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Cool Title</title>
    <!-- bower:css -->
    <!-- endbower -->
</head>
<body>


<!-- bower:js -->
<!-- endbower -->
</body>
</html>

And now execute the Grunt command :

grunt bowerInstall

This will modify your index.html file and generate this one :

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Cool Title</title>
    <!-- bower:css -->
    <link rel="stylesheet" href="../bower_components/asciidoctor.js/dist/css/asciidoctor.css" />
    <!-- endbower -->
</head>
<body>

<!-- bower:js -->
<script src="../bower_components/jquery/dist/jquery.js"></script> (1)
<script src="../bower_components/bootstrap/dist/js/bootstrap.js"></script>
<script src="../bower_components/opal/opal/current/opal.js"></script> (1)
<script src="../bower_components/asciidoctor.js/dist/asciidoctor.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-core.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-extensions.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-docbook.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-all.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor.min.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-core.min.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-extensions.min.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-docbook.min.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-all.min.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor.min.gz.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-core.min.gz.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-extensions.min.gz.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-docbook.min.gz.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-all.gz.js"></script>
<!-- endbower -->
</body>
</html>
  1. As you can see, dependencies requirements are also automatically added.

As you can see some JavaScript files seems to be added but not needed and I also guess that the CSS files for Bootstrap are missing …​

WHY ???

Simply because the grunt-bower-install plugin look in dependencies bower.json ‘s files for the main files, and it add them to your file…​ We will need to adjust that « main » section.

Overriding main section

For « overriding » the main section you can add an « overrides » section in your bower.json file (in your project root directory) :

bower.json

{
  "name": "projectName",
  "version": "0.0.1",
  "author": "Remi goyard",
  "license": "MIT",
  "description": "The Cool Description",
  "main": "",
  "homepage": "",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components"
  ],
  "overrides": { (1)
    "asciidoctor.js": {
      "main": [
        "dist/asciidoctor-all.min.js",
        "dist/css/asciidoctor.css"
      ]
    },
    "bootstrap": {
      "main": [
        "dist/js/bootstrap.min.js",
        "dist/css/bootstrap.min.css",
        "dist/css/bootstrap-theme.min.css"
      ]
    }
  }
}
  1. Will override some dependencies properties.

And then execute again the grunt command :

grunt bowerInstall

Which will generate the following index.html file :

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Cool Title</title>
    <!-- bower:css -->
    <link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap-theme.min.css" />
    <link rel="stylesheet" href="../bower_components/asciidoctor.js/dist/css/asciidoctor.css" />
    <!-- endbower -->
</head>
<body>

<!-- bower:js -->
<script src="../bower_components/jquery/dist/jquery.js"></script>
<script src="../bower_components/bootstrap/dist/js/bootstrap.js"></script>
<script src="../bower_components/opal/opal/current/opal.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-all.min.js"></script>
<!-- endbower -->
</body>
</html>

YEAAHHH !!

Now we have what we expected !

Automatic update

The last thing is to automate the grunt task execution when we add some dependencies.

We will use the grunt-contrib-watch plugin :

npm install grunt-contrib-watch --save-dev

Then you edit the Gruntfile.js :

Gruntfile.js

/*global module:false*/
module.exports = function (grunt) {

    // Project configuration.
    grunt.initConfig({

        bowerInstall: {

            target: {
                src: [
                    'app/index.html'   // .html support...
                ],

                // Optional:
                // ---------
                cwd: '',
                dependencies: true,
                devDependencies: false,
                exclude: [],
                fileTypes: {},
                ignorePath: '',
                overrides: {}
            }
        },
        watch: { (1)
            files: ['bower.json'],
            tasks: ['default'],
        },
    });

    grunt.loadNpmTasks('grunt-contrib-watch');(2)
    grunt.loadNpmTasks('grunt-bower-install');
    // Default task.
    grunt.registerTask('default', ['bowerInstall', 'watch']); (3)

};
  1. You add the task configuration, each time the bower.json is modified, we tell the plugin to run the default task
  2. We load the grunt plugin
  3. Then we add the watch after the bowerInstall execution, this way, the script will watch again for modifications.

So now, if you run the command :

terminal 1

grunt

terminal 2

bower install angular --save

The bowerInstall grunt task is ran and the angular.js dependency is added to the index.html file …

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Cool Title</title>
    <!-- bower:css -->
    <link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap-theme.min.css" />
    <link rel="stylesheet" href="../bower_components/asciidoctor.js/dist/css/asciidoctor.css" />
    <!-- endbower -->
</head>
<body>

<!-- bower:js -->
<script src="../bower_components/jquery/dist/jquery.js"></script>
<script src="../bower_components/bootstrap/dist/js/bootstrap.js"></script>
<script src="../bower_components/opal/opal/current/opal.js"></script>
<script src="../bower_components/asciidoctor.js/dist/asciidoctor-all.min.js"></script>
<script src="../bower_components/angular/angular.js"></script> (1)
<!-- endbower -->
</body>
</html>
  1. The angular dependency automatically added.

Conclusion

Quite easy to do and very convenient !

Vous aimerez aussi...

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *