Silencing JSLint warnings in brackets - angularjs
I just started a gulp-angular Yeoman project and opened it in brackets, and nearly everywhere I'm getting 'something' was used before it was defined, specifically 'angular' was used before it was defined. I've messed around with extensions and other fixes, but I honestly don't know what I'm doing and I haven't been able to find any good documentation.
What can I do to silence these warnings across the entire project? In other words, how can I avoid using /*global angular*/ in pretty much every file in my project?
Here's a quick example of one of my controller declarations:
/*global console*/
(function () {
'use strict';
angular
.module('sbk')
.controller('MainController', MainController);
/** #ngInject */
function MainController() {
console.log('Woo!');
}
})();
Which results in the following JSLint warnings:
'angular' was used before it was defined.
'MainController' was used before it was defined.
'MainController' was used before it was defined.
Move the invocation into the parens that contain the function.
Edit: updated to make my issue a little clearer
http://jshint.com/docs/options/#globals
Provide a list of globals, and you're done.
It's not clear if you're using jshint or jslint; your tags say one, your text another.
Okay, so remember that JSLint is just a JavaScript file, and most JSLint plugins I've used has the source shoved in the install somewhere (though the Visual Studio plugin embeds it into a dll!), so you can always get it to do what you want [within reason].
In your case, the absolute worst case is that you initialize the list of predefined variables with the namespaces you want JSLint to assume are always considered to be in scope. I'm going to show you how to set that globally within Brackets, which might not always be the best thing to do, and you need to keep in mind if you're linting another project that doesn't have Angular, well, you've screwed up JSLint.
(Honestly, I'm disappointed that Brackets doesn't have global as a global in its preferences.json file. Guess I should submit a patch.)
There are lots of ways we could do this. I'm going to add a namespace to the standard object. You could also limit its exposure by adding to the browser collection of globals (line 497 in my Bracket install's jslint file). We could also create a new JSLint directive option, similar to browser. That's not quick 'n' dirty, but is probably The Right Way to do this without submitting a Brackets patch. But for now, let's just do the quick 'n' dirty fix.
I'm using Windows. If you're not, YMWV. I do not use Brackets daily, so I haven't tested this in a production coding environment. If anything doesn't work, I'd be interested to hear it, however, and I'll see if I can find what's wrong.
TL;DR. Just the code, ma'am.
The jslint.js file you want is here, if you went with the default install location:
C:\Program Files (x86)\Brackets\www\extensions\default\JSLint\thirdparty\jslint
(Just for fun, notice that the version of JSLint we're using is from 2011!!?! Come on, Brackets guys!)
standard is, in my file, on line 974. Here's what it had originally:
// standard contains the global names that are provided by the
// ECMAScript standard.
standard = array_to_object([
'Array', 'Boolean', 'Date', 'decodeURI', 'decodeURIComponent',
'encodeURI', 'encodeURIComponent', 'Error', 'eval', 'EvalError',
'Function', 'isFinite', 'isNaN', 'JSON', 'Math', 'Number', 'Object',
'parseInt', 'parseFloat', 'RangeError', 'ReferenceError', 'RegExp',
'String', 'SyntaxError', 'TypeError', 'URIError'
], false),
Here's a test JavaScript snippet I want to lint that uses my global object, util:
/*jslint sloppy:true, white:true */
utils.spam();
utils.spammySpam();
smutils.spam();
All we need to do is to add , 'utils' to standard, and we're done.
standard = array_to_object([
'Array', 'Boolean', 'Date', 'decodeURI', 'decodeURIComponent',
'encodeURI', 'encodeURIComponent', 'Error', 'eval', 'EvalError',
'Function', 'isFinite', 'isNaN', 'JSON', 'Math', 'Number', 'Object',
'parseInt', 'parseFloat', 'RangeError', 'ReferenceError', 'RegExp',
'String', 'SyntaxError', 'TypeError', 'URIError', 'utils'
], false),
To be overly clear, you'd add 'angular' and 'MainController' to your standard object in place of 'utils'.
Btw, Crockford (JSLint's creator and maintainer) would hate that we did that. I don't really blame him.
Now I get an error for smutils, but not utils. Luckily, the global directive still works with this setup:
/*jslint sloppy:true, white:true */
/*global smutils */
utils.spam();
utils.spammySpam();
smutils.spam();
And we're JSLint friendly again.
Hacking JSLint directly might not have most favored option status, but it works.
Btw, re: Dave's comment, "IMO JSLint has been popularly deprecated in favor of JSHint or JSCS," I'm not so sure. Just as an example, which does Brackets use out of the box? The best part about JSLint is how much less subjective discussion has to happen to get a large team on the same page. And trust me, Crockford's not going to tell you to do something that's indefensibly wrong.
He might hurt your feelings, and he might ask you to do something that hurts at first, but I really think JSLint can teach a team a lot about JavaScript best practices. It's worth living in JSLint for a while before jumping to JSHint.
Related
React: Disable minification for a given library
I am in the process of testing the release build of a react native app and found that the minification process is breaking the xml parser library. In this case, there is a [ReferenceError: Can't find variable: dc], which I found out by diving through the minified bundle and logging, to be related to the above referenced library. Is there a way to disable minification only for this library? Also, would this be the best approach to tackle this kinds of minification problems?
Disable minification for React App What is the current behavior? When bundling production builds for React Native, names are mangled by default. This can break code (if it relies on Function.name) and the issue is kinda hard to track down (especially if the code accessing Function.name is deep into your dependency tree). What is the expected behavior? There should be at least an option to disable mangling, but I believe ideally it should be opt-in rather than opt-out. (Since it can break code in unpredictable ways) For now relying on manually patching minify.js Solved by disabling mangling: Prevent UglifyJS from changing function argument names. According to the documentation you can use mangle options to do that: mangle (default true) — pass false to skip mangling names, or pass an object to specify mangling options. Object options: except - pass an Array of identifiers that should be excluded from mangling toplevel — mangle names declared in the toplevel scope (disabled by default). eval — mangle names visible in scopes where eval or with are used (disabled by default). keep_fnames - default false. Pass true to not mangle function names. Useful for code relying on Function.prototype.name. in node_modules/metro-bundler/src/JSTransformer/worker/minify.js function minify(filename, code, sourceMap) { const minifyResult = uglify.minify(code, { fromString: true, inSourceMap: sourceMap, outSourceMap: true, mangle: false, // ADD THIS LINE output: { ascii_only: true, screw_ie8: true, }, }); }) OR May be your issue is due to the combination of running webpack -p and using Uglify Plugin. Try omitting -p when running build and use uglify plugin, might this fix your issue.
when defining an angular module - should I wrap in self executing function?
(function (angular) { "use strict"; angular.module('module') .filter('leFilter', function() { ... }); })(angular); Saw this code in a new project I'm working on. I usually just begin the module at the root of the file and dont use 'strict' mode. angular.module('module') .filter('leFilter', function() { ... }); I've never ran into a single issue doing this. In the context of an angular application, is there really anything to gain from the self-executing function and 'strict' mode?
I really don't see any major benefit from running it in an IIFE(Immediately-Invoked Function Expression), especially with how good angular is about wrapping things in closures itself (such as in your filter). You will insulate yourself from naming collisions thanks to the scope created by using them, but they decrease readability. They would be a bit more useful in this regard if you stored your angular modules in variables upon instantiation and used those when adding controllers/filters/etc. rather than using the module getter, but I don't recommend doing that. If you are using a build system such as Gulp or Grunt then it might be worth having it compile these files inside of IIFE, and leaving your source without them. I always recommend using "use strict" because it makes you write cleaner code with less chance of having casting issues. But, again, it doesn't necessarily help you "gain" anything so much as it prevents something bad from possible occurring. Both of these are essentially safe-guards more-so than giving you some sort of advantage.
strict mode means you have less chance of running into type casting issue while self executing function is to avoid polluting global namespace.
Managing Angular Module names in a large project
I'm working on a a large scale angular project with a team of devs. the problem we run into is if you have several files for a component, say a directive. some-directive.js some-directive-controller.js in the definition of both files you would have to attach them to a module, however one file must create the module with []. If the developer forgets to poke around they will add [] in the second file called will actually overwrite the module. so now it becomes a memory game. Each developer has to remember to only declare the module in one file [] some-directive.js angular.module('some-module',['some-dependencies']).directive('some-directive',function(){}); some-controller.js angular.module('some-module',[]).controller('some-controller',function(){}); we have been using the following approach. Is there a better way? some-directive.js some-directive-module.js some-directive-controller.js where some-directive-module only contains the module creation, includes any dependencies, and does any .config needed. Still the dev needs to remember to angular.module('some-directive') in all the other files without the square brackets. some-directive-module.js angular.module('some-directive',[]) .config(//someconfig stuff); some-directive-module.js angular.module('some-directive).directive(//declare directive); some-directive-controller.js angular.module('some-directive).controller(//declare contrller used by directive); I suggested that instead we should do the following, it eliminates the issue of overwriting modules, but I received some negative feedback from one of the other devs some-directive-module.js angular.module('some-directive',['some-directive.directive','some-directive.controller']) .config(//someconfig stuff); some-directive-module.js angular.module('some-directive.directive',[]).directive(//declare directive); some-directive-controller.js angular.module('some-directive.controller',[]).controller(//declare contrller used by directive); Is there a better way? Or is one of the above options correct?
The recommended way (by multiple competent people) is to use the setter-getter-syntax (creating once with angular.module("someModule",[]) and accessing with angular.module("someModule") from there on). Putting the module definition and configuration into one file seems very clean and is common practice between a lot of developers. But make sure not to create a module for every single directive - group services, directives, constants and so on into reasonable functionality-modules instead. Making clear what a file contains by its name is also a good idea in my opinion, so your some-directive-module.js approach seems fine to me. If developers "poke around" and "wildly add []", they should get a slap on the wrist follwoed by an explanation how modules work in angular, so they stop doing it ;-)
Why are global functions considered "wrong" in Angular 1.3
Traditionally I have managed my Angular code like this //File 1 angular.module('name',[]) //File 2 function TestController(){ } TestController.prototype.// inherited stuff angular.module('name').controller('testController',TestController); This worked great and allowed me to partition my files easily. Now I try to upgrade to 1.3 and get the infamous... Error: [ng:areq] Argument 'TestController' is not a function, got undefined Of course this is due to this change which claims a desire to clean up the way people write code. What about this pattern is more complex? Is there a way to maintain this pattern without changing the global settings?
There is actually a comment on the page you linked to that had a fairly solid explanation. Global controllers refer to your controllers being defined as function on the window object. This means that they are openly available to conflict with any other bit of JavaScript that happens to define a function with the same name. Admittedly, if you post-fix your controllers with ...Controller then this could well not happen but there is always the chance, especially if you were to use a number of 3rd party libraries. It is much safer to put these controller functions inside the safety of a module. You then have more control over when and where this module gets loaded. Unfortunately controller names are global across an individual Angular app and so you still have the potential for conflict but at least you can't clash with completely different code in the JavaScript global namespace. So the idea is that global controller functions could conflict with any other global function in any javascript you use. So to eliminate the chance of a conflict with your own code or a third-party script, not using global controllers makes your code safer and more consistent. As mentioned in the comments by #Brett, you can use IIFE around your prototyping. Here is an update of your plunk that uses that. The main change just looks like this. (function() { TestController.prototype.name = 'World' })();
What comes to my mind is 2 things: 1) in that way functions wont be kept in memory more than they should. 2) if you minify your code, minifyer will have to generate new names for all global objects, which is sfine when you have small project, but will be a problem when it's not. Also it should prevent tests to modify unnecessary data.
AngularJS - when defining a module, what is the meaning of third argument when it is an array?
I am new to AngularJS. I have been reading the excellent book Mastering Web Application Development with AngularJS by Pawel Kozlowski and Peter Bacon Darwin. However, I am still a bit fuzzy on some concepts, so I have decided to go through their sample application line by line to try and get a better understanding of how AngularJS is used in a real-world app. In some places I see notation that I can't see explained in their book, nor in the API docs. I am wondering if anyone can shed some light on this, as seen in the /client/src/app/projectsinfo/projectsinfo.js file of the project linked to above: angular.module('projectsinfo', [], ['$routeProvider', function($routeProvider){ ... }]); My understanding of the angular.module method is that it accepts three arguments: the name of the module an array of other modules that this module might depend on an optional configuration function However, in the above example, for the third argument an array is being provided, with the first element in the array being a string (I am assuming a provider?), followed by a function. Can anyone explain what is going on here?
The syntax of angular.module() is: angular.module(name, [requires], configFn); where: name is the name of the module, requires is an optional list of modules on which this module depends, and configFn is a function used to configure the module. Here the configFn can be a function or a array: If it is a function, then the dependencies injected to it will be injected based on the name of the parameters. If it is an array, then we can use the array to specify the name of the services that need to be injected and then use some other name as the function parameter. This is useful when your code might be obfuscated by a minifier. The code in the said files seems to be fine.