AngularJS design guide - javascript

Previously when I was writing angular apps, I used to do
angular.module('ngApp', ['all', 'required', 'ng*', 'dependencies'])
in my app.js and then inside services/ and controllers, I could simply do:
angular.module('ngApp')
I have a repo to demonstrate that.
But then I saw the angular-seed/, the way implemented was,
in controllers/
angular.module('appControllers', ['dependencies'])...
in services/
angular.module('appServices', ['dependencies'])..
in app.js
angular.module('ngApp', ['ng*', 'appControllers', 'appSrvices'])..
I had no issue with design, infact I thought it was good, since evrything was dependency injected as well as modular.
I have a situation where I have a services/movie.js that has
angular.module('myAppServices', ['ngResource']).factory(..)
and services/config.js
angular.module('myAppServices').factory(..)
But while writing tests with karma and jasmine. In the karma.conf.js,
I had
files: ['usual', 'bower_components/angular-*.js', 'app/services/**/*.js', '..']
but the problem was config.js got loaded before movie.js and there were errors, myAppServices is not loaded or mis-spelt.
The way I fixed it was I did:
files: ['..', 'app/services/movie.js', 'app/services/config.js']
I have set up a github repo for this too. Here is the controller test file and here is the karma.conf.
I want to know what can be the possible approaches to take such modular approach, without having to specify the order in which the files are to be loaded for my tests.
And this is my first unit test, and its failing:
Error: Unexpected request: GET https://api.themoviedb.org/3/configuration?api_key=2e329c92227ed8be07944ae447c9426f
Expected GET https://api.themoviedb.org/3/movie/top_rated?api_key=2e329c92227ed8be07944ae447c9426f
It would be helpful if I could get some help in fixing that too.
The test
describe('Controllers', function() {
beforeEach(module('myApp'));
beforeEach(module('myAppServices'));
describe("MoviesCtrl", function() {
var scope, ctrl, httpBackend;
beforeEach(inject(function($httpBackend, $rootScope, _$controller_, Movie, Config) {
httpBackend = $httpBackend;
ctrl = _$controller_;
scope = $rootScope.$new();
}));
it("should return a list of movies", function() {
var data = {results: [{name: "Abc"}, {name: "Def"}]};
httpBackend.
expectGET("https://api.themoviedb.org/3/movie/top_rated?api_key=2e329c92227ed8be07944ae447c9426f").
respond(data);
ctrl('MoviesCtrl', { $scope: scope });
httpBackend.flush()
expect(scope.image).toEqual("https://api.themoviedb.org/3/");
});
});
});
conf. file
module.exports = function(config) {
config.set({
basePath: './',
frameworks: ['jasmine'],
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/bower_components/angular-resource/angular-resource.js',
'app/bower_components/angular-route/angular-route.js',
'app/services/movie.js',
'app/services/config.js',
'app/controllers/*.js',
'app/app.js',
'unit-tests/**/*.js'
],
exclude: [
'app/**/*.min.js'
],
preprocessors: {
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};
UPDATE
I have figured out the error in test, I had to mock the other http request for the configuration. thanks to #Phil.
This is my test now:
describe('Controllers', function() {
beforeEach(module('myApp'));
beforeEach(module('myAppServices'));
describe("MoviesCtrl", function() {
var scope, httpBackend;
var config_data = { images: { base_url: "http://tmdb.com/t/p", backdrop_sizes: ["w300", "w500"]}},
movie_data = {results: [{name: "Abc"}, {name: "Def"}]};
beforeEach(inject(function($httpBackend, $rootScope, $controller) {
httpBackend = $httpBackend;
scope = $rootScope.$new();
httpBackend.
expectGET("https://api.themoviedb.org/3/configuration?api_key=2e329c92227ed8be07944ae447c9426f").
respond(config_data);
httpBackend.
expectGET("https://api.themoviedb.org/3/movie/top_rated?api_key=2e329c92227ed8be07944ae447c9426f").
respond(movie_data);
$controller('MoviesCtrl', { $scope: scope });
}));
it("should return a list of movies", function() {
expect(scope.image).toEqual({})
httpBackend.flush();
expect(scope.image.backdrop_size).toEqual("w300");
});
});
});
Although I am not sure if this is the right test to do :P . Something like a VCR would be helpful.

Why use two separate files for 10 lines each? The purpose of writing code in separate files is to keep it understandable and maintainable. It would make sense to keep your module 'myAppServices' in one file.
If you really need to break down your code in multiple files, you should make use of dependency injection and make them each a separate module (see my patch against your repo). Then the order of loading stops being an issue.

I still haven't found a angular-ish solution to this problem.
Still there are two ways to deal with it.
Using RequireJS as in #Lukasz 's blog post
and the second one is a dirty one, which I did,
Wrote an _config.js file inside services/, controllers/, directives/, which has, for example angular.module('myAppServices', ['ngResource']) in services/,
And in the karma.config.js I had to do files: ['app/services/_config.js', 'app/controllers/_config.js] . Although the problem still remains because I have to specify the order in which the two _config.js's are to be loaded.
Another way could be to have a single app/config.js file with,
(function() {
angular.module('myAppServices', ['ngResource']);
angular.module('myAppControllers', ['myAppServices']);
}());
and then do files: ['app/config.js', 'app/controllers/**/*.js', 'app/services/**/*.js'] in karma.conf.js

Related

Unit testing AngularJS application with karma-browserify

I'm trying to unit test an AngularJS/Browserify application via karma-browserify. Ultimately, when I run my gulp karma task, I get the error Error: [$injector:nomod] Module 'myApp' is not available! You either misspelled the module name or forgot to load it...
My gulpfile.js has the task
gulp.task('test', function(done) {
new karma.Server({
configFile: __dirname + '/karma.conf.js'
}, done).start();
});
My karma.conf.js includes
{
// ...
frameworks: ['browserify', 'jasmine'],
files: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'spec/**/*.js'
],
preprocessors: {
'spec/**/*.js': [ 'browserify' ]
},
browserify: {
debug: true
}
// ...
}
I define my module in a main.js that includes
require('angular').module('myApp', [
//...lots of `require`s for each dependency...
]);
I define my controller in a MainCtrl.js that looks like
function MainCtrl(/*...deps...*/) {
var ctrl = this;
ctrl.foo = 'bar';
}
module.exports = MainCtrl;
then register the controller elsewhere like
var app = require('angular').module('myApp');
app.controller('MainCtrl', [/*...deps...*/, require('./MainCtrl')]);
Finally my test looks like
(function() {
"use strict";
describe('MainCtrl', function() {
var ctrl;
beforeEach( angular.mock.module('myApp') );
beforeEach( inject( function($controller) {
ctrl = $controller('MainCtrl');
}));
it('should be defined', function() {
expect(ctrl).toBeDefined();
});
});
}());
Workaround
The workaround I have is to add my main.js file to karma.conf.js
files: [
'js/main.js', // ADDED: Defines the app and `require`s angular
'node_modules/angular-mocks/angular-mocks.js',
'spec/**/*.js'
],
preprocessors: {
'js/main.js': ['browserify'], // ADDED
'spec/**/*.js': ['browserify']
}
and everything works. But I thought I wasn't supposed to add my source files to karma (at least not with karma-browserify). Is this the right way to set up my project?
Yes, the 'workaround' is the desired way to use karma-browserify.
preprocessors definition specifies which of the included files should be processed by which preprocessor but does not include them:
The keys of the preprocessors config object are used to filter the
files specified in the files configuration.
it is files definition that actually includes the files:
The files array determines which files are included in the browser and
which files are watched and served by Karma.
Files tells Karma which files it should load relative to the base path. These are:
All test related libraries
Our source code to test
The tests themselves

Karma: Angular Module Mocking

I am currently trying to write karma unit tests for a controller in an angular app. For me the desired result is to load ONLY the controller which I am testing (assume for now I only ever want to test this one controller) and have all other dependencies mocked out for me.
To set the stage:
I have a module: 'XYZ' defined in js/xyz_module.js
I have a module: 'ABC' defined in js/abc_module.js
module 'ABC' is dependent on 'XYZ'
module 'ABC' has a controller: 'AbcController' defined in js/abc_controller.js
my testing is to be done ONLY on 'AbcController'
karma.conf.js:
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
'node_modules/angular/angular.js',
'node_modules/angular-mocks/angular-mocks.js',
'js/abc_module.js',
'js/controllers/abc_controller.js',
'spec/karma/abc_controller_spec.js'
],
...
abc_module.js:
angular.module('ABC', ['XYZ']);
abc_controller.js:
angular.module('ABC').controller('AbcController', ['$scope', function($scope) {
$scope.letters = ['a', 'b', 'c']
}]);
abc_controller_spec.js:
describe('AbcController', function() {
beforeEach(function() {
angular.mock.module('XYZ');
module('ABC')
});
var $controller;
beforeEach(inject(function(_$controller_) {
$controller = _$controller_
}));
describe('$scope.letters', function() {
it("is set to three letters", function() {
var $scope = {};
$controller('AbcController', {$scope: $scope});
expect($scope.letters.length).toEqual(3)
})
})
});
My theory was that, since module XYZ is a mocked module that I should NOT have to include js/xyz_module.js in my karam.conf.js file, but that the mocking framework would simply mock it for me. Unfortunately this does not seem to be the case. When I run karma I get an error that it cannot find the module 'XYZ'. Is there any way around this? If I have to include all dependencies even to test a portion of an application, it will make it exponentially more difficult with more complex applications. Obviously this is a contrived example and the project I am actually working with involves many modules with many dependencies, making it exceedingly difficult to test portions of it if I have to effectively include the whole application. I thought that was the whole point of mocking? Am I missing something?
After further research I think I now realise that angular.mock.module does not actually CREATE a module but is used to initialise an existing module. As such, if I create an additional mock file with: angular.module('XYZ',[]);, add it to karma.conf.js and THEN do beforeEach(angular.mock.module('XYZ')); that seems to work. One baby step forward. The next step is mocking any dependencies that 'XYZ' has and that my 'ABC' module uses, but that is probably another question.

Setting up Jasmine/karma for angular

I am lightly following this guide - http://paislee.io/testing-angularjs-with-grunt-karma-and-jasmine/ - and having a few issues as follows:
Error: [$injector:modulerr] Failed to instantiate module myApp due to:
Error: [$injector:modulerr] Failed to instantiate module ngRoute due to:
Error: [$injector:nomod] Module 'ngRoute' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
I installed everything as it told me to and found another pretty basic example of setting up a test(this is my first time implementing so I'm starting small), the test looks like so
describe('Unit: MainCtrl', function() {
// Load the module with MainCtrl
beforeEach(module('myApp'));
var ctrl, scope;
// inject the $controller and $rootScope services
// in the beforeEach block
beforeEach(inject(function($controller, $rootScope) {
// Create a new scope that's a child of the $rootScope
scope = $rootScope.$new();
// Create the controller
ctrl = $controller('MainCtrl', {
$scope: scope
});
}));
it('should create $scope.greeting when calling sayHello',
function() {
expect(scope.greeting).toBeUndefined();
scope.sayHello();
expect(scope.greeting).toEqual("Hello Ari");
});
})
And in the controller it's just
$scope.name = "Ari";
$scope.sayHello = function() {
$scope.greeting = "Hello " + $scope.name;
}
(this is from http://www.ng-newsletter.com/advent2013/#!/day/19 )
I have my app set up and controllers in separate folders, using a regular ng-route structure, I'm thinking this maybe is the issue? I'm using grunt karma for this - here is the task just incase it's helpful.
karma: {
unit: {
options: {
frameworks: ['jasmine'],
singleRun: true,
browsers: ['PhantomJS'],
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/scripts/**/*.js'
]
}
}
}
I could use some help, this is my first time attempting this, I would LOVE to get some automated testing in place. Thanks for reading!!
You need to include ngRoute in your files list in the karma conf. The error message says as much.
karma: {
unit: {
options: {
frameworks: ['jasmine'],
singleRun: true,
browsers: ['PhantomJS'],
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/bower_components/angular-mocks/angular-route.js',
'app/scripts/**/*.js'
]
}
}
}
You have not included ngroute module, as there is some dependency on this module.
There should be a bower component
'app/bower_components/angular-route/angular-route.js',
Install this bower component and add this line to karma config.
Check for other module too.

UI Router Extras breaks my unit tests with unexpected results error?

QUESTION:
- Why are my tests failing when ui-router-extras (not normal ui-router) is install?
- How can I use ui-router-extras and still have my tests pass?
If you want to install this quickly use yeoman + angular-fullstack-generator + bower install ui-router-extras
I found a similar issue with normal ui-router.
Luckially, ui-router normal works just fine with my testing.
After installing ui-router-extras I get an ERROR
If I uninstall ui-router.extras it this test passes just fine:
UPDATED for beforeEach module of $urlRouterProvider TEST
Heres my test:
'use strict';
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('morningharwoodApp'));
beforeEach(module('socketMock'));
var MainCtrl,
scope,
$httpBackend;
// Initialize the controller and a mock scope
beforeEach(
inject( function (_$httpBackend_, $controller, $rootScope) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('/api/things')
.respond(['HTML5 Boilerplate', 'AngularJS', 'Karma', 'Express']);
scope = $rootScope.$new();
MainCtrl = $controller('MainCtrl', {
$scope: scope
});
}),
module(function ($urlRouterProvider) {
$urlRouterProvider.otherwise( function(){ return false; });
})
);
it('should attach a list of things to the scope', function () {
$httpBackend.flush();
expect(scope.awesomeThings.length).toBe(4);
});
});
Here's my karma.conf
module.exports = function(config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'client/bower_components/jquery/dist/jquery.js',
'client/bower_components/angular/angular.js',
'client/bower_components/angular-mocks/angular-mocks.js',
'client/bower_components/angular-resource/angular-resource.js',
'client/bower_components/angular-cookies/angular-cookies.js',
'client/bower_components/angular-sanitize/angular-sanitize.js',
'client/bower_components/lodash/dist/lodash.compat.js',
'client/bower_components/angular-socket-io/socket.js',
'client/bower_components/angular-ui-router/release/angular-ui-router.js',
'client/bower_components/famous-polyfills/classList.js',
'client/bower_components/famous-polyfills/functionPrototypeBind.js',
'client/bower_components/famous-polyfills/requestAnimationFrame.js',
'client/bower_components/famous/dist/famous-global.js',
'client/bower_components/famous-angular/dist/famous-angular.js',
'client/app/app.js',
'client/app/app.coffee',
'client/app/**/*.js',
'client/app/**/*.coffee',
'client/components/**/*.js',
'client/components/**/*.coffee',
'client/app/**/*.jade',
'client/components/**/*.jade',
'client/app/**/*.html',
'client/components/**/*.html'
],
preprocessors: {
'**/*.jade': 'ng-jade2js',
'**/*.html': 'html2js',
'**/*.coffee': 'coffee',
},
ngHtml2JsPreprocessor: {
stripPrefix: 'client/'
},
ngJade2JsPreprocessor: {
stripPrefix: 'client/'
},
// list of files / patterns to exclude
exclude: [],
// web server port
port: 8080,
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['PhantomJS'],
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};
This might be a result of some component having a dependency on $state in which case $state will be instantiated and default route will be executed. This is why a template of one of your controllers main.html is being fetched.
To bypass this, replace go() and transitionTo() of $state methods with dummies:
beforeEach( inject( function ( _$state_ ) {
state = _$state_;
spyOn( state, 'go' );
spyOn( state, 'transitionTo' );
} ) );
Here's an alternate solution that doesn't nuke ui-router's transitionTo function.
First, the failing scenario can be reproduced by following these steps:
npm install yo generator-angular-fullstack;
yo angular-fullstack
Inject $state service by adding this line to client/app/app.js:
angular.module("yoAppName").run(function($state) {});
At this point, invoking grunt karma reports the Unexpected request: GET app/main/main.html because UI-Router is bootstrapped and tries to load the default route, which requests the route's template.
To address this, tell UI-Router to delay synchronizing the URL to the state, so we don't load the default route. In the controller spec, add $urlRouterProvider.deferIntercept(); to your test init code:
beforeEach(module('uiRouterExtrasKarmaBugApp'));
// Add the following line
beforeEach(module(function($urlRouterProvider) { $urlRouterProvider.deferIntercept(); }));
1) Your test is failing because ui-router-extras is making an unexpected http GET request to app/main/main.html therefore test fails.
2) Actually there are a lot of suggestions in the issue that you linked to. I assume extra call is made to load the template for the default route, ie. otherwise. So overriding it might fix the problem:
beforeEach(module(function ($urlRouterProvider) {
$urlRouterProvider.otherwise(function(){return false;});
}));
There are two solutions actually... Right after the module declaration.
you can add:
beforeEach(module('stateMock'));
or you can manually, defer the intercept:
beforeEach(module(function($urlRouterProvider) { $urlRouterProvider.deferIntercept(); }));

Angular.module minification bug

Having the darnedest time trying to figure out why minification is not working.
I have injected via an array object my providers prior the function per numerous suggestions across the web and yet still "Unknown provider: aProvider <- a"
Regular:
var app = angular.module('bpwApp', ['ui.bootstrap', 'ui', 'myTabs'])
.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider){
$routeProvider.
when('/', {templateUrl: 'partials/home.jade', controller: HomeCtrl});
$locationProvider.html5Mode(true);
}])
Minified:
var app = angular.module('bpwApp', ['ui.bootstrap', 'ui', 'myTabs'])
.config(['$routeProvider', '$locationProvider', function(a, b){
a.
when('/', {templateUrl: 'partials/home.jade', controller: HomeCtrl});
b.html5Mode(true);
}])
Any suggestion would be much obliged!
I ran into this problem before with Grunt.js Uglify plugin.
One of the options are mangle
uglify: {
options: {
mangle: false
},
Which I believe runs regex functions on "like strings" and minifys them.
For example:
angular.module("imgur", ["imgur.global","imgur.album"]);
Would become:
angular.module("a", ["a.global","a.album"]);
Disable it --- this feature doesn't play nice with Angular.
Edit:
To be more precise as #JoshDavidMiller explains:
Uglify mangle only mangles like variables, which is what actually causes the AngularJS problem. That is, the problem is in injection and not definition.
function MyCtrl($scope, myService) would get mangled to function MyCtrl(a, b), but the service definition inside of a string should never get altered.
Running ng-min before running uglify solves this problem.
Problem
From AngularJS: The Bad Parts:
Angular has a built in dependency injector that will pass appropriate
objects to your function based on the names of its parameters:
function MyController($scope, $window) {
// ...
}
Here, the names of the parameters $scope and $window will be
matched against a list of known names, and corresponding objects get
instantiated and passed to the function. Angular gets the parameter
names by calling toString() on the function, and then parsing the
function definition.
The problem with this, of course, is that it stops working the
moment you minify your code. Since you care about user experience
you will be minifying your code, thus using this DI mechanism will
break your app. In fact, a common development methodology is to use
unminified code in development to ease debugging, and then to minify
the code when pushing to production or staging. In that case, this
problem won’t rear its ugly head until you’re at the point where it
hurts the most.
(...)
Since this dependency injection mechanism doesn’t actually work in the
general case, Angular also provides a mechanism that does. To be sure,
it provides two. You can either pass along an array like so:
module.controller('MyController', ['$scope', '$window', MyController]);
Or you can set the $inject property on your constructor:
MyController.$inject = ['$scope', '$window'];
Solution
You can use ng-annotate for auto adding annotations required for minifying:
ng-annotate adds and removes AngularJS dependency injection
annotations. It is non-intrusive so your source code stays exactly the
same otherwise. No lost comments or moved lines.
ng-annotate is faster and stabler than ngmin (which is now deprecated) and it has plugins for many tools:
grunt-ng-annotate
gulp-ng-annotate
browserify-annotate
Starting from AngularJS 1.3 there's also a new param in ngApp called ngStrictDi:
if this attribute is present on the app element, the injector will be
created in "strict-di" mode. This means that the application will fail
to invoke functions which do not use explicit function annotation (and
are thus unsuitable for minification), as described in the Dependency
Injection guide, and useful debugging info will assist in tracking
down the root of these bugs.
I got same error. However, for me, the problem is directives' controller declaration. You should do this instead.
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
templateUrl: 'directive.html',
replace: false,
restrict: 'A',
controller: ["$scope", "$element", "$attrs", "$transclude", "otherInjectables",
function($scope, $element, $attrs, $transclude, otherInjectables) { ... }]
};
return directiveDefinitionObject;
});
https://github.com/angular/angular.js/pull/3125
I had a similar issue using grunt, ngmin and uglify.
I ran the process in this order: concat, ngmin, uglify
I was continuing to get the $injector error from angular until I added in the uglify options mangle: false - then everything was fixed.
I also tried to add the exceptions to uglify like this:
options: {
mangle: {
except: ['jQuery', 'angular']
}
}
But to no avail...
Here is my gruntFile.js for further clarification:
module.exports = function(grunt) {
'use strict';
// Configuration goes here
grunt.initConfig({
pkg: require('./package.json'),
watch: {
files: ['scripts/**/*.js', 'test/**/*spec.js', 'GruntFile.js'],
tasks: ['test', 'ngmin']
},
jasmine : {
// Your project's source files
src : ['bower_components/angular/angular.js', 'bower_components/angular-mocks/angular-mocks.js', 'scripts/app.js', 'scripts/**/*.js' ],
// Your Jasmine spec files
options : {
specs : 'test/**/*spec.js',
helpers: 'test/lib/*.js'
}
},
concat: {
dist : {
src: ['scripts/app.js', 'scripts/**/*.js'],
dest: 'production/js/concat.js'
}
},
ngmin: {
angular: {
src : ['production/js/concat.js'],
dest : 'production/js/ngmin.js'
}
},
uglify : {
options: {
report: 'min',
mangle: false
},
my_target : {
files : {
'production/app/app.min.js' : ['production/js/ngmin.js']
}
}
},
docular : {
groups: [],
showDocularDocs: false,
showAngularDocs: false
}
});
// Load plugins here
grunt.loadNpmTasks('grunt-ngmin');
grunt.loadNpmTasks('grunt-docular');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-connect');
// Define your tasks here
grunt.registerTask('test', ['jasmine']);
grunt.registerTask('build', ['concat', 'ngmin', 'uglify']);
grunt.registerTask('default', ['test', 'build', 'watch']);
};
AndrewM96 suggestion of ng-min is right.
The alignment and white space matters to Uglify as well as Angular.
I had a similar problem. And solved it the following way. We need to run a Gulp module called gulp-ng-annotate before we run uglify.
So we install that module
npm install gulp-ng-annotate --save-dev
Then do the require in Gulpfile.js
ngannotate = require(‘gulp-ng-annotate’)
And in your usemin task do something like this
js: [ngannotate(), uglify(),rev()]
That solved it for me.
[EDIT: Fixed typos]
Uglify has an option to disable mangling on specific files:
options: {
mangle: {
except: ['jQuery', 'angular']
}
}
https://github.com/gruntjs/grunt-contrib-uglify#reserved-identifiers
This is very difficult to debug because a lot of services are named the same (mostly e or a). This will not solve the error, but will provide you with the name of the unresolved service which enables you to track down, in the uglified output, the location in the code and finally enables you to solve the issue:
Go into lib/scope.jsof Uglify2 (node_modules/grunt-contrib-uglify/node_modules/uglify-js/lib/scope.js) and replace the line
this.mangled_name = this.scope.next_mangled(options);
with
this.mangled_name = this.name + "__debugging_" + counter++

Categories

Resources