Giter Site home page Giter Site logo

angular-annotate-sweetjs's Introduction

AngularJS DI Annotation with Sweet.js

Annotating AngularJS DI-able functions with Sweet.js:

The Problem

AngularJS' dependency injection system uses the parameters of a function to determine which dependencies to inject. For example:

app.controller('SomeController', function($scope, $http) {
  // ...
});

Instances of SomeController will automatically be passed instances of the $scope and $http services because those are the services named in the parameter list. The problem comes after minifying; the code above might be turned into something like

a.controller('SomeController', function(b, c) {
  // ...
});

Angular has no way of knowing what b and c used to be, so your dependency injection breaks.

Manual Annotation

Angular provides a workaround—any function that works with its injector can also be specified as an array where the first elements match up with the names of the services, and the function can take parameters of any name. For instance,

app.controller('SomeController', ['$scope', '$http', function($scope, $http) {
  // ...
}]);

might be turned into

a.controller('SomeController', ['$scope', '$http', function(b, c) {
  // ...
}]);

and Angular knows what to inject based on the strings in the array.

The problem with this solution is that it is error prone; the array gets out of sync with the function parameters, and the injection breaks again.

ngmin

Brian Ford created a great Node.js library called ngmin that detects many common function definitions and automatically converts them into array-annotated functions for you.

However, ngmin inspects the AST and tries to intelligently guess whether the functions you've provided should be annotated. This works great for the built-in common cases, like .controller and .factory, but not so great in less common ones like the resolve functions of routers, or manual calls to $injector.invoke.

Even with a pluggable annotation system, which would allow users to write their own custom AST passes, keeping track of all the various places that functions are defined and then invoked by the injector is difficult and brittle.

Sweet.js

The solution I've developed here is based on Sweet.js, which allows you to write macros for JavaScript. I've created a di macro that, when passed a function, will emit an array-annotated function for you.

This is the macro:

macro di {
  case { _ ( function ($params:ident (,) ...) { $body ...} ) } => {
    var tokens = #{$params...}.map(function(t) { return makeValue(t.token.value, #{here}) });
    letstx $annotations... = tokens;
    return #{
      [ $annotations (,) ... , function ($params ...) {
        $body ...
      } ]
    }
  }
}

To use, simply wrap any function declaration that needs to work with the injector in di(). The macro will convert code like this:

app.controller('SomeController', di(function($scope, $http, $injector) {
  $http.get('...');
}));

into this:

app.controller('SomeController', [
  '$scope',
  '$http',
  '$injector',
  function ($scope, $http, $injector) {
    $http.get('...');
  }
]);

You can also use the macro with function references; simply wrap the function declaration (not the invocation).

var fn = di(function($rootScope) {
});
$injector.invoke(fn);

is converted into

var fn = ['$rootScope', function ($rootScope) {
}];
$injector.invoke(fn);

The use case is similar to ngmin—run this on your unminified code before you minify it. There are Sweet.js plugins on npm for Grunt, Gulp, and Browserify, and the Sweet.js API is super easy to use, so it shouldn't be too hard to run in other contexts.

While the process is not as automatic as something like ngmin, as you do need to remember to use the di macro, it will automatically keep the array up to date as the parameters change and is not subject to most of the drawbacks of an AST detection system like ngmin.

Demo

Check out the macro on the Sweet.js web site; you can also check out this CoffeeScript version I built based off the same code.

angular-annotate-sweetjs's People

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

angular-annotate-sweetjs's Issues

Use "export di;" for use with Gulp.js

The macro will not function when export di; is ommitted at the end of the the macro. Add it and it will work like a charm. Kudos @BinaryMuse

I've added the macro below at macros/angular-annotate-sweetjs.sjs. One directory up is where my gulpfile.coffee resides.

macro di {
  case { _ ( function ($params:ident (,) ...) { $body ...} ) } => {
    var tokens = #{$params...}.map(function(t) { return makeValue(t.token.value, #{here}) });
    letstx $annotations... = tokens;
    return #{
      [ $annotations (,) ... , function ($params ...) {
        $body ...
      } ]
    }
  }
}
export di;

Example usage with Gulp:

gulp.src './src/**/*.coffee'
    .pipe coffee bare: true 
    .pipe sweetjs modules: ['./macros/angular-annotate-sweetjs']
    .pipe gulp.dest '.tmp'

Versions used:

  • Gulp: 3.6.1
  • gulp-sweetjs: 0.3.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.