Search code examples
angularjsgulpbrowserifyhammer.js

Gulp throws an error when bundling angular and angular-hammer with browserify


Gulp throws an unclear error when I am trying to bundle angular and angular-hammer (the Ryan Mullins version) with browserify.

For a stripped down version of the app, the package.json file is:

{
  "name": "hammer-test",
  "version": "0.0.0",
  "description": "",
  "main": "app/main.js",
  "devDependencies": {
    "browserify": "^10.2.1",
    "browserify-shim": "^3.8.7",
    "gulp": "^3.8.11",
    "vinyl-source-stream": "^1.1.0"
  },
  "dependencies": {
    "angular": "^1.3.15",
    "angular-hammer": "^2.1.10",
    "hammerjs": "^2.0.4"
  }
}

(I included browserify-shim, because an error was thrown asking for this missing dependency for angular-hammer.)

The gulpfile.js contains a bundle task to run browserify:

'use strict';

var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');

// Bundle (browserify).
gulp.task('bundle', function() {

    return browserify('./app/js/main.js')
        .bundle()
        .pipe(source('bundle.js'))
        .pipe(gulp.dest('./dist/js'));
});

gulp.task('default', ['bundle']);

And finally, the main javascript file app/js/main.js contains:

(function() {
    'use strict';

    // Require stuff.
    var angular = require('angular');
    var Hammer = require('hammerjs');
    require('angular-hammer');

    // Initialize angular application.
    var app = angular.module('myApp', ['hmTouchEvents']);

}());

The directory structure of the app now looks like this:

- app
  - js
    -main.js
- node_modules
  - angular
  - angular-hammer
  - browserify
  - browserify-shim
  - gulp
  - hammerjs
  - vinyl-source-stream
- gulpfile.js
- package.json

When I now try to run the bundle task using the command:

gulp

Then the following error is thrown:

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: ENOENT, open '/home/brennerd/Develop/hammer-test/node_modules/angular-hammer/node_modules/angular/angular.js'

The error is not very descriptive, but some paths seem to be incorrectly concatenated. Did I make a browserify mistake somewhere? My browserify experience is limited, so that could very well be the case. Or is it not possible to bundle angular-hammer with browserify?

Thanks!


Solution

  • After some searching, learning, and playing around I found the issue. It was indeed a browserify mistake.

    Thanks to the documentation of the angular-hammer-propagating fork I figured out that the package.json needed some extension. As far as I understand to 1) let browserify know that it should run browserify-shim and 2) to let browserify-shim know where to find the angular-hammer dependencies. The package.json now looks like this:

    {
      "name": "hammer-test",
      "version": "0.0.0",
      "description": "",
      "main": "app/main.js",
      "devDependencies": {
        "browserify": "^10.2.1",
        "browserify-shim": "^3.8.7",
        "gulp": "^3.8.11",
        "vinyl-source-stream": "^1.1.0"
      },
      "dependencies": {
        "angular": "^1.3.15",
        "angular-hammer": "^2.1.10",
        "hammerjs": "^2.0.4"
      },
      "browserify": {
        "transform": [
          "browserify-shim"
        ]
      },
      "browser": {
        "angular-hammer": "./node_modules/angular-hammer/angular.hammer.js"
      },
      "browserify-shim": {
        "angular-hammer": {
          "exports": "angular.module('hmTouchEvents').name",
          "depends": [
            "./node_modules/hammerjs/hammer.js:Hammer"
          ]
        }
      }
    }
    

    For testing I added a HammerTestCtrl with the handleTap function to the main.js file:

    (function() {
        'use strict';
    
        // Require both angular and angular-hammer.
        var angular = require('angular');
        require('angular-hammer');
    
        // Initialize angular application.
        var app = angular.module('myApp', ['hmTouchEvents']);
    
        // Add controller to test hammer.
        app.controller('HammerTestCtrl', ['$scope', function($scope) {
    
            $scope.handleTap = function() {
    
                console.log('Tap detected.');
            }    
        }]);
    
    }());
    

    I created a basic index.html with a square div that calls the handleTap function when it is tapped:

    <!DOCTYPE html>
    <html lang="en" ng-app="myApp">
    
      <head>
        <meta charset="utf-8">
        <title>Test hammer-angular</title>
        <script src="js/bundle.js"></script>
    
      </head>
    
      <body ng-controller="HammerTestCtrl">
        <div hm-tap="handleTap" style="width: 300px; height: 300px; background-color: #eeeeec;"></div>
      </body>
    
    </html>
    

    And in the gulpfile.js I added a task to move this index.html from the app to the dist directory:

    'use strict';
    
    var browserify = require('browserify');
    var gulp = require('gulp');
    var source = require('vinyl-source-stream');
    
    // Bundle (browserify).
    gulp.task('bundle', function() {
    
        return browserify('./app/js/main.js')
            .bundle()
            .pipe(source('bundle.js'))
            .pipe(gulp.dest('./dist/js'));
    });
    
    // HTML.
    gulp.task('html', function() {
    
        gulp.src('app/index.html')
            .pipe(gulp.dest('dist/'));
    });
    
    gulp.task('default', ['bundle', 'html']);
    

    After an npm install and this time successful gulp, the directory structure looks like this:

    - app
      - index.html
      - js
        -main.js
    - dist
      - index.html
      - js
        - bundle.js
    - node_modules
      - angular
      - angular-hammer
      - browserify
      - browserify-shim
      - gulp
      - hammerjs
      - vinyl-source-stream
    - gulpfile.js
    - package.json
    

    After browsing to the dist/index.html file it correctly outputs Tap detected. to the console every time the light-gray square is tapped. The code for this angular-hammer boilerplate web application can be found here.