Recently when deploying one of my projects to heroku, I came across a problem. Half of my site wasn’t working. Specifically, all the links to my site that connected to the backend end were not being routed properly. It took me an obscenely long amount of time and a lot of trial and error to finally arrive at the actual problem.
Minification
I built my project to be a single page app with an AngularJS front end with a Rails API back end. Angular controllers under go something called minification when the website is deployed in a production environment. This helps to reduce file sizes so resources load faster in live environments by renaming long variable names. So the following
would become
That’s awesome! But what’s not awesome is when you deploy your site and forget about annotating dependency injection. The process of shortening variable names isn’t so awesome when your controllers are dependent on other controllers, services, directives, and components. All of those names get minified too, but you probably don’t have any angular providers called a, b, c
but more like PostsController, UserService, $http
. After minification, angular will look for a, b, c
and your controllers start to break. In my case, I had some resolve
data that needed to be injected in on state changes from ui.router. So my app.js
file looks something like
and my PostsController could look something like
The Solution: Safe Dependency Injection
The solution to get around this is to properly use the $inject
function to tell angular that we are expecting our dependencies in a specific order. The order here is all that matters, we can name it whatever we’d like i.e.
Notice the line PostsController.$inject = ['posts', 'categories', '$filter'];
. The array that gets injected and matches the order of dependencies in the line function PostsController(random, variables, foobar)
. It doesn’t matter what we name elements here, angular just knows that that the first element injected 'posts'
will correspond to the first argument 'random'
and 'categories'
will correspond to 'variables'
and so on.
On the app.js
side, annotation would look something like
Once I injected all my dependencies across my various controllers/components/directives/services, site started routing properly like it did in development! The lesson here? If you plan to deploy a production version of your angular site, make sure you properly annotate your dependencies! Or just use ng-annotate.