Home » Nodejs » Concat bower components with grunt

Concat bower components with grunt

Posted by: admin November 30, 2017 Leave a comment

Questions:

I’m building an application which require few front-end lib/frameworks such as:

  • jQuery
  • JQueryUI
  • AngularJS
  • Foundation

I’m using bower to download the components. At this moment my HTML looks like:

<script src="components/jquery/jquery.js"></script>
<script src="components/angular/angular.js"></script>
<script src="components/etc/etc.js"></script>

My goal is to make a grunt script which automatically takes the installed components, concat and minify them and output them as lib.js.

Questions:

With all my researches I figure out how to concat all files from a directory.
My goal here is to get the bower components and concat them without listing them one by one in the gruntfile. How I can archieve this?

Also Is it possible to make a custom jQuery UI build with just the modules I want instead of having the entire UI.

Thanks.

Answers:

“My goal here is to get the bower components and concat them without listing them one by one in the gruntfile”

You can take all javascript files from your dependencies directory and sub-directories, and have them concatenated that way:

grunt.config('concat.mydeps', {
  files: [{
    src: ['components/**/*.js'],
    dest: 'dist/lib.js'
  }]
})

… but if the order of script execution is important, this is a recipe for disaster :-).

Also, it’s quite likely that these folder would contain minified and non minified versions, leading you to include some scripts twice…

A way to avoid that side effect would be in the line of:

grunt.config('concat.mydeps', {
  files: [{
    src: ['components/**/*.js', '!components/**/*min.js'],
    dest: 'dist/lib.js'
  }]
})

… but again, this is certainly not bulletproof – a given component may very well have a builded version, and a splitted source alongside.

IMHO, the only sane way out is to list explicitly the files you want aggregated, in the order you need (just like you do in your html for now).

Questions:
Answers:

usemin is your friend here.

Install usemin, copy, concat and uglify:

npm install --save-dev grunt-usemin
npm install --save-dev grunt-contrib-copy
npm install --save-dev grunt-contrib-concat
npm install --save-dev grunt-contrib-uglify

Set up a build block in your HTML file:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>usemin</title>
  <!-- build:js lib.js -->
    <script src="components/jquery/jquery.js"></script>
    <script src="components/angular/angular.js"></script>
    <script src="components/etc/etc.js"></script>
  <!-- endbuild -->
</head>
<body>
<h1>usemin</h1>
</body>
</html>

Set up your Gruntfile:

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    copy: {
      dist: {
        files: [ {src: 'index.html', dest: 'dist/index.html'} ]
      }
    },

    'useminPrepare': {
      options: {
        dest: 'dist'
      },
      html: 'index.html'
    },

    usemin: {
      html: ['dist/index.html']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-usemin');

  grunt.registerTask('default', ['useminPrepare', 'copy', 'concat', 'uglify', 'usemin']);
};

Run grunt

grunt

Results:

├── Gruntfile.js
├── components
│   ├── angular
│   │   └── angular.js
│   ├── etc
│   │   └── etc.js
│   └── jquery
│       └── jquery.js
├── dist
│   ├── index.html
│   └── lib.js
├── index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>usemin</title>
  <script src="lib.js"></script>
</head>
<body>
<h1>usemin</h1>
</body>
</html>