Angular "Unknown Provider" error after minification with Grunt Build in Yeoman app

javbotero picture javbotero · Dec 3, 2013 · Viewed 16.2k times · Source

I'm having problems with grunt build on a Yeoman generated Angular app, using Coffee and Slim, with all libraries up-to-date. (The app was just generated a few days ago with the most recent generator.)

grunt build and grunt server both worked fine initially. But after a few days of development using grunt server, I discovered that grunt build had stopped working entirely.

There were a few different problems that I fixed. The biggest one was that I had to abandon Slim entirely for my index file and use straight HTML, since grunt build was inexplicably removing 80% of the index file when it published to /dist.

Unfortunately, after I got almost everything resolved, I started getting this error in one of my Angular directives:

Uncaught Error: Unknown provider: aProvider <- a

The problem seems to be in uglify. I think it could possibly be the same problem reported here, but I'm not absolutely sure. I tried a number a number of solutions, but the only thing that has worked for me was to manually generate clean js files from my coffeescript, copy the files into /dist, and then write the paths into dist/index.html.

Obviously that's not optimal. I'm sure there's a neater way to do it in Grunt (probably by removing minification entirely from the build process, as that other user did in the link above), but I'm new to it and haven't yet figured out how to do that. Either way, it would be a workaround.

My Gruntfile is pretty basic: I've only added grunt-connect-proxy, grunt-contrib-sass, and grunt-slim to the default file. In fact, I tried to bring in a clean, newly-generated Gruntfile but it didn't build any better.

The directive that's failing is below. The error actually comes up right in the first line of the controller, $scope.showInput = false. What's frustrating is that everything works great in grunt server. The moment I build though, it falls apart entirely.

myModule.directive "editable", ->

  controller = ($scope) ->
    $scope.showInput = false

    $scope.saveContent = -> 
      $scope.toggleContent()
      $scope.save()

  linker = (scope, element, attrs) ->    
    scope.toggleContent = -> 
      scope.showInput = not scope.showInput
      setTimeout((-> element.find('input').focus()), 100)

  return DDO = 
    restrict: 'E'
    controller: controller
    link: linker
    templateUrl: "template/editable.html"
    scope:
      editableType: "@"
      text: "="
      placeholder: "@"
      save: "&"

(The template isn't really important. It just has an ng-switch that toggles using $scope.showInput.)

If anybody has any suggestions, I'd appreciate it.

Answer

m59 picture m59 · Dec 3, 2013

It sounds like the common issue of Angular's reliance on the name of arguments for dependency injection. Make sure when you pass dependencies that you include the dependency names as strings so that Angular will know what to inject after minification (since string values won't be changed in the minification process).

myApp.controller('myCtrl', ['$scope', '$http', function($scope, $http) {

}])

From Angular docs: A Note on minification